cache_inode_status_t cache_inode_kill_entry( cache_entry_t * pentry, cache_inode_lock_how_t lock_how, hash_table_t * ht, cache_inode_client_t * pclient, cache_inode_status_t * pstatus ) { fsal_handle_t *pfsal_handle = NULL; cache_inode_fsal_data_t fsaldata; cache_inode_parent_entry_t *parent_iter = NULL; cache_inode_parent_entry_t *parent_iter_next = NULL; hash_buffer_t key, old_key; hash_buffer_t old_value; int rc; fsal_status_t fsal_status; memset( (char *)&fsaldata, 0, sizeof( fsaldata ) ) ; LogInfo(COMPONENT_CACHE_INODE, "Using cache_inode_kill_entry for entry %p", pentry); /* Invalidation is not for junctions or special files */ if( ( pentry->internal_md.type == FS_JUNCTION ) || ( pentry->internal_md.type == SOCKET_FILE ) || ( pentry->internal_md.type == FIFO_FILE ) || ( pentry->internal_md.type == CHARACTER_FILE ) || ( pentry->internal_md.type == BLOCK_FILE ) ) { free_lock( pentry, lock_how ) ; *pstatus = CACHE_INODE_SUCCESS; return *pstatus; } #if 0 /** @todo: BUGAZOMEU : directory invalidation seems quite tricky, temporarily avoid it */ if( pentry->internal_md.type == DIRECTORY ) { free_lock( pentry, lock_how ) ; *pstatus = CACHE_INODE_SUCCESS; return *pstatus; } /** @todo: BUGAZOMEU : file invalidation seems quite tricky, temporarily avoid it */ /* We need to know how to manage how to deal with "files with states" */ if( pentry->internal_md.type == REGULAR_FILE ) { free_lock( pentry, lock_how ) ; *pstatus = CACHE_INODE_SUCCESS; return *pstatus; } #endif if(pstatus == NULL) return CACHE_INODE_INVALID_ARGUMENT; if(pentry == NULL || pclient == NULL || ht == NULL) { free_lock( pentry, lock_how ) ; *pstatus = CACHE_INODE_INVALID_ARGUMENT; return *pstatus; } /* Get the FSAL handle */ if((pfsal_handle = cache_inode_get_fsal_handle(pentry, pstatus)) == NULL) { free_lock( pentry, lock_how ) ; LogCrit(COMPONENT_CACHE_INODE, "cache_inode_kill_entry: unable to retrieve pentry's specific filesystem info"); return *pstatus; } /* Invalidate the related LRU gc entry (no more required) */ if(pentry->gc_lru_entry != NULL) { if(LRU_invalidate(pentry->gc_lru, pentry->gc_lru_entry) != LRU_LIST_SUCCESS) { free_lock( pentry, lock_how ) ; *pstatus = CACHE_INODE_LRU_ERROR; return *pstatus; } } fsaldata.handle = *pfsal_handle; fsaldata.cookie = DIR_START; /* Use the handle to build the key */ if(cache_inode_fsaldata_2_key(&key, &fsaldata, pclient)) { free_lock( pentry, lock_how ) ; LogCrit(COMPONENT_CACHE_INODE, "cache_inode_kill_entry: could not build hashtable key"); cache_inode_release_fsaldata_key(&key, pclient); *pstatus = CACHE_INODE_NOT_FOUND; return *pstatus; } /* use the key to delete the entry */ if((rc = HashTable_Del(ht, &key, &old_key, &old_value)) != HASHTABLE_SUCCESS) { if( rc != HASHTABLE_ERROR_NO_SUCH_KEY) /* rc=3 => Entry was previously removed */ LogCrit( COMPONENT_CACHE_INODE, "cache_inode_kill_entry: entry could not be deleted, status = %d", rc); cache_inode_release_fsaldata_key(&key, pclient); *pstatus = CACHE_INODE_NOT_FOUND; return *pstatus; } /* Release the hash key data */ cache_inode_release_fsaldata_key(&old_key, pclient); /* Clean up the associated ressources in the FSAL */ if(FSAL_IS_ERROR(fsal_status = FSAL_CleanObjectResources(pfsal_handle))) { LogCrit(COMPONENT_CACHE_INODE, "cache_inode_kill_entry: Couldn't free FSAL ressources fsal_status.major=%u", fsal_status.major); } /* 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, "cache_inode_kill_entry: unexpected pdata %p from hash table (pentry=%p)", old_value.pdata, pentry); } /* Release the current key */ cache_inode_release_fsaldata_key(&key, 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, &pclient->pool_parent); parent_iter = parent_iter_next; } /* If entry is datacached, remove it from the cache */ if(pentry->internal_md.type == REGULAR_FILE) { cache_content_status_t cache_content_status; if(pentry->object.file.pentry_content != NULL) if(cache_content_release_entry ((cache_content_entry_t *) pentry->object.file.pentry_content, (cache_content_client_t *) pclient->pcontent_client, &cache_content_status) != CACHE_CONTENT_SUCCESS) LogCrit(COMPONENT_CACHE_INODE, "Could not removed datacached entry for pentry %p", pentry); } /* If entry is a DIRECTORY, invalidate dirents */ if(pentry->internal_md.type == DIRECTORY) { cache_inode_invalidate_related_dirents(pentry, pclient); } // free_lock( pentry, lock_how ) ; /* Really needed ? The pentry is unaccessible now and will be destroyed */ /* Destroy the mutex associated with the pentry */ cache_inode_mutex_destroy(pentry); /* Put the pentry back to the pool */ ReleaseToPool(pentry, &pclient->pool_entry); *pstatus = CACHE_INODE_SUCCESS; return *pstatus; } /* cache_inode_kill_entry */
main(int argc, char *argv[]) { char localmachine[256]; cache_inode_client_t client; LRU_parameter_t lru_param; LRU_status_t lru_status; cache_inode_fsal_data_t fsdata; fsal_status_t status; fsal_parameter_t init_param; fsal_name_t name; fsal_path_t path; fsal_attrib_mask_t mask; fsal_path_t pathroot; fsal_attrib_list_t attribs; fsal_handle_t root_handle; cache_inode_endofdir_t eod_met; cache_inode_dir_entry_t dirent_array[100]; cache_inode_dir_entry_t dirent_array_loop[5]; unsigned int nbfound; unsigned int begin_cookie = 0; hash_buffer_t key, value; uid_t uid; fsal_cred_t cred; cache_inode_status_t cache_status; cache_inode_parameter_t cache_param; cache_inode_client_parameter_t cache_client_param; hash_table_t *ht = NULL; fsal_attrib_list_t attrlookup; cache_entry_t *cache_entry_root = NULL; cache_entry_t *cache_entry_lookup = NULL; cache_entry_t *cache_entry_lookup2 = NULL; cache_entry_t *cache_entry_lookup3 = NULL; cache_entry_t *cache_entry_lookup4 = NULL; cache_entry_t *cache_entry_dircont = NULL; cache_inode_gc_policy_t gcpol; char *configfile = argv[1]; int i = 0; int rc = 0; /* Init the Buddy System allocation */ if((rc = BuddyInit(NULL)) != BUDDY_SUCCESS) { LogTest("Error initializing memory allocator"); exit(1); } /* init debug */ SetDefaultLogging("TEST"); SetNamePgm("test_cache_inode"); SetNameFunction("main"); InitLogging(); #if defined( _USE_GHOSTFS ) if(argc != 2) { LogTest("Please set the configuration file as parameter"); exit(1); } #endif /* Obtention du nom de la machine */ if(gethostname(localmachine, sizeof(localmachine)) != 0) { LogError(COMPONENT_STDOUT,ERR_SYS, ERR_GETHOSTNAME, errno); exit(1); } else SetNameHost(localmachine); AddFamilyError(ERR_FSAL, "FSAL related Errors", tab_errstatus_FSAL); AddFamilyError(ERR_CACHE_INODE, "FSAL related Errors", tab_errstatus_cache_inode); /* creating log */ LogTest( "Starting the test"); LogTest( "-----------------"); #if defined( _USE_GHOSTFS ) if(FSAL_IS_ERROR(status = FSAL_str2path(configfile, strlen(configfile) + 1, &(init_param.fs_specific_info. definition_file)))) { LogError(COMPONENT_STDOUT,ERR_FSAL, status.major, status.minor); } #elif defined( _USE_HPSS ) FSAL_SET_INIT_DEFAULT(init_param.fs_specific_info, Flags); FSAL_SET_INIT_DEFAULT(init_param.fs_specific_info, DebugValue); FSAL_SET_INIT_DEFAULT(init_param.fs_specific_info, TransferType); FSAL_SET_INIT_DEFAULT(init_param.fs_specific_info, NumRetries); FSAL_SET_INIT_DEFAULT(init_param.fs_specific_info, BusyDelay); FSAL_SET_INIT_DEFAULT(init_param.fs_specific_info, BusyRetries); FSAL_SET_INIT_DEFAULT(init_param.fs_specific_info, TotalDelay); FSAL_SET_INIT_DEFAULT(init_param.fs_specific_info, GKTotalDelay); FSAL_SET_INIT_DEFAULT(init_param.fs_specific_info, LimitedRetries); FSAL_SET_INIT_DEFAULT(init_param.fs_specific_info, MaxConnections); FSAL_SET_INIT_DEFAULT(init_param.fs_specific_info, ReuseDataConnections); FSAL_SET_INIT_DEFAULT(init_param.fs_specific_info, UsePortRange); FSAL_SET_INIT_DEFAULT(init_param.fs_specific_info, RetryStageInp); FSAL_SET_INIT_DEFAULT(init_param.fs_specific_info, DMAPWriteUpdates); FSAL_SET_INIT_DEFAULT(init_param.fs_specific_info, ServerName); FSAL_SET_INIT_DEFAULT(init_param.fs_specific_info, DescName); init_param.fs_specific_info.behaviors.PrincipalName = FSAL_INIT_FORCE_VALUE; strncpy(init_param.fs_specific_info.hpss_config.PrincipalName, HPSS_SSM, HPSS_MAX_PRINCIPAL_NAME); init_param.fs_specific_info.behaviors.KeytabPath = FSAL_INIT_FORCE_VALUE; strncpy(init_param.fs_specific_info.hpss_config.KeytabPath, HPSS_KEYTAB, HPSS_MAX_PATH_NAME); FSAL_SET_INIT_DEFAULT(init_param.fs_specific_info, DebugPath); FSAL_SET_INIT_DEFAULT(init_param.fs_specific_info, HostName); FSAL_SET_INIT_DEFAULT(init_param.fs_specific_info, RegistrySiteName); #endif /* 2-common info (default) */ FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, maxfilesize); FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, maxlink); FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, maxnamelen); FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, maxpathlen); FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, no_trunc); FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, chown_restricted); FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, case_insensitive); FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, case_preserving); FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, fh_expire_type); FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, link_support); FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, symlink_support); FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, named_attr); FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, unique_handles); FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, lease_time); FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, acl_support); FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, cansettime); FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, homogenous); FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, maxread); FSAL_SET_INIT_DEFAULT(init_param.fs_common_info, maxwrite); /* Init */ if(FSAL_IS_ERROR(status = FSAL_Init(&init_param))) { LogError(COMPONENT_STDOUT,ERR_FSAL, status.major, status.minor); } /* getting creds */ uid = getuid(); if(FSAL_IS_ERROR(status = FSAL_GetUserCred(uid, NULL, &cred))) { LogError(COMPONENT_STDOUT,ERR_FSAL, status.major, status.minor); } /* Init of the cache inode module */ cache_param.hparam.index_size = 31; cache_param.hparam.alphabet_length = 10; /* Buffer seen as a decimal polynom */ cache_param.hparam.nb_node_prealloc = 100; cache_param.hparam.hash_func_key = cache_inode_fsal_hash_func; cache_param.hparam.hash_func_rbt = cache_inode_fsal_rbt_func; cache_param.hparam.hash_func_both = NULL ; /* BUGAZOMEU */ cache_param.hparam.compare_key = cache_inode_compare_key_fsal; cache_param.hparam.key_to_str = display_key; cache_param.hparam.val_to_str = display_value; if((ht = cache_inode_init(cache_param, &cache_status)) == NULL) { LogTest( "Error %d while init hash ", cache_status); } else LogTest( "Hash Table address = %p", ht); /* We need a cache_client to acces the cache */ cache_client_param.attrmask = FSAL_ATTRS_MANDATORY | FSAL_ATTR_MTIME | FSAL_ATTR_CTIME | FSAL_ATTR_ATIME; cache_client_param.nb_prealloc_entry = 1000; cache_client_param.nb_pre_dir_data = 200; cache_client_param.nb_pre_parent = 1200; cache_client_param.nb_pre_state_v4 = 100; cache_client_param.lru_param.nb_entry_prealloc = 1000; cache_client_param.lru_param.entry_to_str = lru_entry_to_str; cache_client_param.lru_param.clean_entry = lru_clean_entry; cache_client_param.grace_period_attr = 0; cache_client_param.grace_period_link = 0; cache_client_param.grace_period_dirent = 0; cache_client_param.expire_type_attr = CACHE_INODE_EXPIRE_NEVER; cache_client_param.expire_type_link = CACHE_INODE_EXPIRE_NEVER; cache_client_param.expire_type_dirent = CACHE_INODE_EXPIRE_NEVER; /* Init the cache_inode client */ if(cache_inode_client_init(&client, cache_client_param, 0, NULL) != 0) exit(1); /* Init the gc */ gcpol.file_expiration_delay = 3; gcpol.directory_expiration_delay = 4; gcpol.hwmark_nb_entries = 6; gcpol.lwmark_nb_entries = 3; gcpol.run_interval = 4; cache_inode_set_gc_policy(gcpol); /* Getting the root of the FS */ if((FSAL_IS_ERROR(status = FSAL_str2path("/", 2, &pathroot)))) { LogError(COMPONENT_STDOUT,ERR_FSAL, status.major, status.minor); exit(1); } if((FSAL_IS_ERROR(status = FSAL_lookupPath(&pathroot, &cred, &root_handle, &attribs)))) { LogError(COMPONENT_STDOUT,ERR_FSAL, status.major, status.minor); exit(1); } fsdata.cookie = 0; fsdata.handle = root_handle; /* Cache the root of the FS */ if((cache_entry_root = cache_inode_make_root(&fsdata, 1, ht, &client, &cred, &cache_status)) == NULL) { LogTest( "Error: can't init fs's root"); exit(1); } /* A lookup in the root fsal */ if((FSAL_IS_ERROR(status = FSAL_str2name("cea", 10, &name)))) { LogError(COMPONENT_STDOUT,ERR_FSAL, status.major, status.minor); exit(1); } if((cache_entry_lookup = cache_inode_lookup(cache_entry_root, &name, &attrlookup, ht, &client, &cred, &cache_status)) == NULL) { LogTest( "Error: can't lookup"); exit(1); } /* Lookup a second time (entry should now be cached) */ if((cache_entry_lookup2 = cache_inode_lookup(cache_entry_root, &name, &attrlookup, ht, &client, &cred, &cache_status)) == NULL) { LogTest( "Error: can't lookup"); exit(1); } if(cache_entry_lookup2 != cache_entry_lookup) { LogTest("Error: lookup results should be the same"); exit(1); } /* A lookup in the root fsal */ if((FSAL_IS_ERROR(status = FSAL_str2name("log", 10, &name)))) { LogError(COMPONENT_STDOUT,ERR_FSAL, status.major, status.minor); exit(1); } if((cache_entry_lookup3 = cache_inode_lookup(cache_entry_root, &name, &attrlookup, ht, &client, &cred, &cache_status)) == NULL) { LogTest( "Error: can't lookup"); exit(1); } if((cache_entry_lookup4 = cache_inode_lookup(cache_entry_root, &name, &attrlookup, ht, &client, &cred, &cache_status)) == NULL) { LogTest( "Error: can't lookup"); exit(1); } if(cache_entry_lookup3 != cache_entry_lookup4) { LogTest("Error: lookup results should be the same"); exit(1); } /* A lookup in the root fsal */ if((FSAL_IS_ERROR(status = FSAL_str2name("SunOS_5", 10, &name)))) { LogError(COMPONENT_STDOUT,ERR_FSAL, status.major, status.minor); exit(1); } cache_inode_print_dir(cache_entry_root); /* Test readdir */ if(cache_inode_readdir(cache_entry_root, 0, 100, &nbfound, &eod_met, dirent_array, ht, &client, &cred, &cache_status) != CACHE_INODE_SUCCESS) { LogTest( "Error: cache_inode_readdir failed"); exit(1); } LogTest( "Readdir nbfound=%d, eod_met=%d", nbfound, eod_met); for(i = 0; i < nbfound; i++) LogTest( "dirent_array[%d] ==> %s | %p", i, dirent_array[i].name.name, dirent_array[i].pentry); cache_inode_print_dir(cache_entry_root); /* looping on readir */ LogTest( "Loop directory in several pass"); eod_met = TO_BE_CONTINUED; begin_cookie = 0; do { if(cache_inode_readdir(cache_entry_root, begin_cookie, 2, &nbfound, &eod_met, dirent_array_loop, ht, &client, &cred, &cache_status) != CACHE_INODE_SUCCESS) { LogTest("Error: cache_inode_readdir failed: %d", cache_status); exit(1); } for(i = 0; i < nbfound; i++) LogTest( " ==> %s | %p", dirent_array_loop[i].name.name, dirent_array_loop[i].pentry); begin_cookie += nbfound; } while(eod_met == TO_BE_CONTINUED); LogTest( "---------------------------------"); /* A lookup in the root fsal */ if((FSAL_IS_ERROR(status = FSAL_str2name("cea", 10, &name)))) { LogError(COMPONENT_STDOUT,ERR_FSAL, status.major, status.minor); exit(1); } if((cache_entry_lookup = cache_inode_lookup(cache_entry_root, &name, &attrlookup, ht, &client, &cred, &cache_status)) == NULL) { LogTest( "Error: can't lookup"); exit(1); } /* A lookup in the root fsal */ if((FSAL_IS_ERROR(status = FSAL_str2name("log", 10, &name)))) { LogError(COMPONENT_STDOUT,ERR_FSAL, status.major, status.minor); exit(1); } if((cache_entry_lookup = cache_inode_lookup(cache_entry_root, &name, &attrlookup, ht, &client, &cred, &cache_status)) == NULL) { LogTest( "Error: can't lookup"); exit(1); } /* Print the Hash Table */ HashTable_Log(COMPONENT_STDOUT, ht); #ifdef _ADDITIONAL_TEST /* Trying to lookup from a DIR_CONTINUE */ fsdata.handle = cache_entry_root->object.dir_begin.handle; fsdata.cookie = 3 * CHILDREN_ARRAY_SIZE; LogTest("Input key: (Handle=%p, Cookie=%d)", fsdata.handle, fsdata.cookie); /* Turn the input to a hash key */ if(cache_inode_fsaldata_2_key(&key, &fsdata, NULL)) { LogTest( "Impossible to allocate a key to that value"); exit(1); } if(HashTable_Get(ht, &key, &value) != HASHTABLE_SUCCESS) { LogTest( "Key could not be found"); exit(1); } /* pentry for the dir cont */ cache_entry_dircont = (cache_entry_t *) value.pdata; /* Test readdir */ if(cache_inode_readdir(cache_entry_dircont, fsdata.cookie, 100, &nbfound, &eod_met, dirent_array, ht, &client, &cred, &cache_status) != CACHE_INODE_SUCCESS) { LogTest( "Error: cache_inode_readdir failed"); exit(1); } #endif LogTest( "Readdir nbfound=%d, eod_met=%d", nbfound, eod_met); for(i = 0; i < nbfound; i++) LogTest( "dirent_array[%d] ==> %s | %p ", i, dirent_array[i].name.name, dirent_array[i].pentry); /* Call the GC */ LogTest( "Sleeping %d second before gc (for gc invalidation)", gcpol.file_expiration_delay + 2); sleep(gcpol.file_expiration_delay + 2); if(cache_inode_gc(ht, &client, &cache_status) != CACHE_INODE_SUCCESS) { LogTest( "Error: cache_inode_gc failed"); exit(1); } LogTest( "GC performed successfully"); /* Print the Hash Table */ HashTable_Log(COMPONENT_STDOUT, ht); /* Another readdir, after gc is made */ eod_met = TO_BE_CONTINUED; begin_cookie = 0; LogTest( "ANOTHER READDIR AFTER GC"); do { if(cache_inode_readdir(cache_entry_root, begin_cookie, 2, &nbfound, &eod_met, dirent_array_loop, ht, &client, &cred, &cache_status) != CACHE_INODE_SUCCESS) { LogTest("Error: cache_inode_readdir failed: %d", cache_status); exit(1); } for(i = 0; i < nbfound; i++) LogTest( " ==> %s | %p", dirent_array_loop[i].name.name, dirent_array_loop[i].pentry); begin_cookie += nbfound; } while(eod_met == TO_BE_CONTINUED); LogTest( "---------------------------------"); /* Print the Hash Table */ HashTable_Log(COMPONENT_STDOUT, ht); LogTest( "---------------------------------"); /* The end of all the tests */ LogTest( "All tests exited successfully"); exit(0); } /* main */
/** * cache_inode_clean_internal: remove a pentry from cache and all LRUs, * and release related resources. * * @param pentry [IN] entry to be deleted from cache * @param hash_table_t [IN] The cache hash table * @param pclient [INOUT] ressource allocated by the client for the nfs management. */ cache_inode_status_t cache_inode_clean_internal(cache_entry_t * to_remove_entry, hash_table_t * ht, cache_inode_client_t * pclient) { fsal_handle_t *pfsal_handle_remove; 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; hash_buffer_t key, old_key, old_value; int rc; memset( (char *)&fsaldata, 0, sizeof( fsaldata ) ) ; if((pfsal_handle_remove = cache_inode_get_fsal_handle(to_remove_entry, &status)) == NULL) { return status; } /* Invalidate the related LRU gc entry (no more required) */ if(to_remove_entry->gc_lru_entry != NULL) { if(LRU_invalidate(to_remove_entry->gc_lru, to_remove_entry->gc_lru_entry) != LRU_LIST_SUCCESS) { return CACHE_INODE_LRU_ERROR; } } /* delete the entry from the cache */ fsaldata.handle = *pfsal_handle_remove; /* XXX always DIR_START */ fsaldata.cookie = DIR_START; if(cache_inode_fsaldata_2_key(&key, &fsaldata, pclient)) { return CACHE_INODE_INCONSISTENT_ENTRY; } /* use the key to delete the entry */ rc = HashTable_Del(ht, &key, &old_key, &old_value); if(rc) LogCrit(COMPONENT_CACHE_INODE, "HashTable_Del error %d in cache_inode_clean_internal", rc); if((rc != HASHTABLE_SUCCESS) && (rc != HASHTABLE_ERROR_NO_SUCH_KEY)) { cache_inode_release_fsaldata_key(&key, pclient); return CACHE_INODE_INCONSISTENT_ENTRY; } /* release the key that was stored in hash table */ if(rc != HASHTABLE_ERROR_NO_SUCH_KEY) { cache_inode_release_fsaldata_key(&old_key, 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 != to_remove_entry) { LogCrit(COMPONENT_CACHE_INODE, "cache_inode_remove: unexpected pdata %p from hash table (pentry=%p)", old_value.pdata, to_remove_entry); } } /* release the key used for hash query */ cache_inode_release_fsaldata_key(&key, pclient); /* Free the parent list entries */ parent_iter = to_remove_entry->parent_list; while(parent_iter != NULL) { parent_iter_next = parent_iter->next_parent; ReleaseToPool(parent_iter, &pclient->pool_parent); parent_iter = parent_iter_next; } return CACHE_INODE_SUCCESS; } /* cache_inode_clean_internal */
/** * * 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 */ }
/** * * cache_inode_get: Gets an entry by using its fsdata as a key and caches it if needed. * * Gets an entry by using its fsdata as a key and caches it if needed. * ASSUMPTION: DIR_CONT entries are always garbabbaged before their related DIR_BEGINNG * * @param fsdata [IN] file system data * @param pattr [OUT] pointer to the attributes for the result. * @param ht [IN] hash table used for the cache, unused in this call. * @param pclient [INOUT] ressource allocated by the client for the nfs management. * @param pcontext [IN] FSAL credentials * @param pstatus [OUT] returned status. * * @return the pointer to the entry is successfull, NULL otherwise. * */ cache_entry_t *cache_inode_get(cache_inode_fsal_data_t * pfsdata, fsal_attrib_list_t * pattr, hash_table_t * ht, cache_inode_client_t * pclient, fsal_op_context_t * pcontext, cache_inode_status_t * pstatus) { hash_buffer_t key, value; cache_entry_t *pentry = NULL; fsal_status_t fsal_status; cache_inode_create_arg_t create_arg; cache_inode_file_type_t type; int hrc = 0; fsal_attrib_list_t fsal_attributes; cache_inode_fsal_data_t *ppoolfsdata = NULL; /* Set the return default to CACHE_INODE_SUCCESS */ *pstatus = CACHE_INODE_SUCCESS; /* stats */ pclient->stat.nb_call_total += 1; pclient->stat.func_stats.nb_call[CACHE_INODE_GET] += 1; /* Turn the input to a hash key */ if(cache_inode_fsaldata_2_key(&key, pfsdata, pclient)) { *pstatus = CACHE_INODE_UNAPPROPRIATED_KEY; /* stats */ pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1; ppoolfsdata = (cache_inode_fsal_data_t *) key.pdata; RELEASE_PREALLOC(ppoolfsdata, pclient->pool_key, next_alloc); return NULL; } switch (hrc = HashTable_Get(ht, &key, &value)) { case HASHTABLE_SUCCESS: /* Entry exists in the cache and was found */ pentry = (cache_entry_t *) value.pdata; /* return attributes additionally */ cache_inode_get_attributes(pentry, pattr); break; case HASHTABLE_ERROR_NO_SUCH_KEY: /* Cache miss, allocate a new entry */ /* If we ask for a dir cont (in this case pfsdata.cookie != FSAL_DIR_BEGINNING, we have * a client who performs a readdir in the middle of a directory, when the direcctories * have been garbbage. we must search for the DIR_BEGIN related to this DIR_CONT */ if(pfsdata->cookie != DIR_START) { /* added for sanity check */ LogDebug(COMPONENT_CACHE_INODE_GC, "=======> Pb cache_inode_get: line %u pfsdata->cookie != DIR_START (=%u) on object whose type is %u", __LINE__, pfsdata->cookie, cache_inode_fsal_type_convert(fsal_attributes.type)); pfsdata->cookie = DIR_START; /* Free this key */ cache_inode_release_fsaldata_key(&key, pclient); /* redo the call */ return cache_inode_get(pfsdata, pattr, ht, pclient, pcontext, pstatus); } /* First, call FSAL to know what the object is */ fsal_attributes.asked_attributes = pclient->attrmask; fsal_status = FSAL_getattrs(&pfsdata->handle, pcontext, &fsal_attributes); if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); LogDebug(COMPONENT_CACHE_INODE_GC, "cache_inode_get: line %u cache_inode_status=%u fsal_status=%u,%u ", __LINE__, *pstatus, fsal_status.major, fsal_status.minor); if(fsal_status.major == ERR_FSAL_STALE) { char handle_str[256]; snprintHandle(handle_str, 256, &pfsdata->handle); LogEvent(COMPONENT_CACHE_INODE_GC,"cache_inode_get: Stale FSAL File Handle %s", handle_str); *pstatus = CACHE_INODE_FSAL_ESTALE; } /* stats */ pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1; /* Free this key */ cache_inode_release_fsaldata_key(&key, pclient); return NULL; } /* The type has to be set in the attributes */ if(!FSAL_TEST_MASK(fsal_attributes.supported_attributes, FSAL_ATTR_TYPE)) { *pstatus = CACHE_INODE_FSAL_ERROR; /* stats */ pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1; /* Free this key */ cache_inode_release_fsaldata_key(&key, pclient); return NULL; } /* Get the cache_inode file type */ type = cache_inode_fsal_type_convert(fsal_attributes.type); if(type == SYMBOLIC_LINK) { FSAL_CLEAR_MASK(fsal_attributes.asked_attributes); FSAL_SET_MASK(fsal_attributes.asked_attributes, pclient->attrmask); fsal_status = FSAL_readlink(&pfsdata->handle, pcontext, &create_arg.link_content, &fsal_attributes); if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); /* stats */ pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1; /* Free this key */ cache_inode_release_fsaldata_key(&key, pclient); if(fsal_status.major == ERR_FSAL_STALE) { cache_inode_status_t kill_status; LogDebug(COMPONENT_CACHE_INODE_GC, "cache_inode_get: Stale FSAL File Handle detected for pentry = %p", pentry); if(cache_inode_kill_entry(pentry, ht, pclient, &kill_status) != CACHE_INODE_SUCCESS) LogCrit(COMPONENT_CACHE_INODE_GC,"cache_inode_get: Could not kill entry %p, status = %u", pentry, kill_status); *pstatus = CACHE_INODE_FSAL_ESTALE; } return NULL; } } /* Add the entry to the cache */ if((pentry = cache_inode_new_entry(pfsdata, &fsal_attributes, type, &create_arg, NULL, /* never used to add a new DIR_CONTINUE within the scope of this function */ ht, pclient, pcontext, FALSE, /* This is a population, not a creation */ pstatus)) == NULL) { /* stats */ pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1; /* Free this key */ cache_inode_release_fsaldata_key(&key, pclient); return NULL; } /* Set the returned attributes */ *pattr = fsal_attributes; /* Now, exit the switch/case and returns */ break; default: /* This should not happened */ *pstatus = CACHE_INODE_INVALID_ARGUMENT; /* stats */ pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1; /* Free this key */ cache_inode_release_fsaldata_key(&key, pclient); return NULL; break; } *pstatus = CACHE_INODE_SUCCESS; /* valid the found entry, if this is not feasable, returns nothing to the client */ P_w(&pentry->lock); if((*pstatus = cache_inode_valid(pentry, CACHE_INODE_OP_GET, pclient)) != CACHE_INODE_SUCCESS) { V_w(&pentry->lock); pentry = NULL; } V_w(&pentry->lock); /* stats */ pclient->stat.func_stats.nb_success[CACHE_INODE_GET] += 1; /* Free this key */ cache_inode_release_fsaldata_key(&key, pclient); return pentry; } /* cache_inode_get */
cache_entry_t *cache_inode_get_located(cache_inode_fsal_data_t * pfsdata, cache_entry_t * plocation, cache_inode_policy_t policy, fsal_attrib_list_t * pattr, hash_table_t * ht, cache_inode_client_t * pclient, fsal_op_context_t * pcontext, cache_inode_status_t * pstatus) { hash_buffer_t key, value; cache_entry_t *pentry = NULL; fsal_status_t fsal_status; cache_inode_create_arg_t create_arg; cache_inode_file_type_t type; int hrc = 0; fsal_attrib_list_t fsal_attributes; cache_inode_fsal_data_t *ppoolfsdata = NULL; memset(&create_arg, 0, sizeof(create_arg)); /* Set the return default to CACHE_INODE_SUCCESS */ *pstatus = CACHE_INODE_SUCCESS; /* stats */ /* cache_invalidate calls this with no context or client */ if (pclient) { pclient->stat.nb_call_total += 1; pclient->stat.func_stats.nb_call[CACHE_INODE_GET] += 1; } /* Turn the input to a hash key */ if(cache_inode_fsaldata_2_key(&key, pfsdata, pclient)) { *pstatus = CACHE_INODE_UNAPPROPRIATED_KEY; /* stats */ /* cache_invalidate calls this with no context or client */ if (pclient) { pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1; ppoolfsdata = (cache_inode_fsal_data_t *) key.pdata; ReleaseToPool(ppoolfsdata, &pclient->pool_key); } return NULL; } switch (hrc = HashTable_Get(ht, &key, &value)) { case HASHTABLE_SUCCESS: /* Entry exists in the cache and was found */ pentry = (cache_entry_t *) value.pdata; /* return attributes additionally */ *pattr = pentry->attributes; if ( !pclient ) { /* invalidate. Just return it to mark it stale and go on. */ return( pentry ); } break; case HASHTABLE_ERROR_NO_SUCH_KEY: if ( !pclient ) { /* invalidate. Just return */ return( NULL ); } /* Cache miss, allocate a new entry */ /* XXX I do not think this can happen with avl dirent cache */ if(pfsdata->cookie != DIR_START) { /* added for sanity check */ LogDebug(COMPONENT_CACHE_INODE, "cache_inode_get: pfsdata->cookie != DIR_START (=%"PRIu64") on object whose type is %u", pfsdata->cookie, cache_inode_fsal_type_convert(fsal_attributes.type)); pfsdata->cookie = DIR_START; /* Free this key */ cache_inode_release_fsaldata_key(&key, pclient); /* redo the call */ return cache_inode_get(pfsdata, policy, pattr, ht, pclient, pcontext, pstatus); } /* First, call FSAL to know what the object is */ fsal_attributes.asked_attributes = pclient->attrmask; fsal_status = FSAL_getattrs(&pfsdata->handle, pcontext, &fsal_attributes); if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); LogDebug(COMPONENT_CACHE_INODE, "cache_inode_get: cache_inode_status=%u fsal_status=%u,%u ", *pstatus, fsal_status.major, fsal_status.minor); if(fsal_status.major == ERR_FSAL_STALE) { char handle_str[256]; snprintHandle(handle_str, 256, &pfsdata->handle); LogEvent(COMPONENT_CACHE_INODE, "cache_inode_get: Stale FSAL File Handle %s, fsal_status=(%u,%u)", handle_str, fsal_status.major, fsal_status.minor); *pstatus = CACHE_INODE_FSAL_ESTALE; } /* stats */ pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1; /* Free this key */ cache_inode_release_fsaldata_key(&key, pclient); return NULL; } /* The type has to be set in the attributes */ if(!FSAL_TEST_MASK(fsal_attributes.supported_attributes, FSAL_ATTR_TYPE)) { *pstatus = CACHE_INODE_FSAL_ERROR; /* stats */ pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1; /* Free this key */ cache_inode_release_fsaldata_key(&key, pclient); return NULL; } /* Get the cache_inode file type */ type = cache_inode_fsal_type_convert(fsal_attributes.type); if(type == SYMBOLIC_LINK) { if( CACHE_INODE_KEEP_CONTENT( policy ) ) { FSAL_CLEAR_MASK(fsal_attributes.asked_attributes); FSAL_SET_MASK(fsal_attributes.asked_attributes, pclient->attrmask); fsal_status = FSAL_readlink(&pfsdata->handle, pcontext, &create_arg.link_content, &fsal_attributes); } else { fsal_status.major = ERR_FSAL_NO_ERROR ; fsal_status.minor = 0 ; } if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); /* stats */ pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1; /* Free this key */ cache_inode_release_fsaldata_key(&key, pclient); if(fsal_status.major == ERR_FSAL_STALE) { cache_inode_status_t kill_status; LogEvent(COMPONENT_CACHE_INODE, "cache_inode_get: Stale FSAL File Handle detected for pentry = %p, fsal_status=(%u,%u)", pentry, fsal_status.major, fsal_status.minor); if(cache_inode_kill_entry(pentry, NO_LOCK, ht, pclient, &kill_status) != CACHE_INODE_SUCCESS) LogCrit(COMPONENT_CACHE_INODE, "cache_inode_get: Could not kill entry %p, status = %u, fsal_status=(%u,%u)", pentry, kill_status, fsal_status.major, fsal_status.minor); *pstatus = CACHE_INODE_FSAL_ESTALE; } return NULL; } } /* Add the entry to the cache */ if ( type == 1) LogCrit(COMPONENT_CACHE_INODE,"inode get"); if((pentry = cache_inode_new_entry( pfsdata, &fsal_attributes, type, policy, &create_arg, NULL, /* never used to add a new DIR_CONTINUE within this function */ ht, pclient, pcontext, FALSE, /* This is a population, not a creation */ pstatus ) ) == NULL ) { /* stats */ pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1; /* Free this key */ cache_inode_release_fsaldata_key(&key, pclient); return NULL; } /* Set the returned attributes */ *pattr = fsal_attributes; /* Now, exit the switch/case and returns */ break; default: /* This should not happened */ *pstatus = CACHE_INODE_INVALID_ARGUMENT; LogCrit(COMPONENT_CACHE_INODE, "cache_inode_get returning CACHE_INODE_INVALID_ARGUMENT - this should not have happened"); if ( !pclient ) { /* invalidate. Just return */ return( NULL ); } /* stats */ pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1; /* Free this key */ cache_inode_release_fsaldata_key(&key, pclient); return NULL; break; } /* Want to ASSERT pclient at this point */ *pstatus = CACHE_INODE_SUCCESS; if (pentry->object.symlink != NULL) { int stop_here; stop_here = 1; if (stop_here) { stop_here = 2; } } /* valid the found entry, if this is not feasable, returns nothing to the client */ if( plocation != NULL ) { if( plocation != pentry ) { P_w(&pentry->lock); if((*pstatus = cache_inode_valid(pentry, CACHE_INODE_OP_GET, pclient)) != CACHE_INODE_SUCCESS) { V_w(&pentry->lock); pentry = NULL; } V_w(&pentry->lock); } } /* stats */ pclient->stat.func_stats.nb_success[CACHE_INODE_GET] += 1; /* Free this key */ cache_inode_release_fsaldata_key(&key, pclient); return pentry; } /* cache_inode_get_located */