cache_inode_status_t cache_inode_readlink(cache_entry_t *entry, fsal_path_t *link_content, fsal_op_context_t *context, cache_inode_status_t *status) { fsal_status_t fsal_status = {0, 0}; /* Set the return default to CACHE_INODE_SUCCESS */ *status = CACHE_INODE_SUCCESS; if (entry->type != SYMBOLIC_LINK) { *status = CACHE_INODE_BAD_TYPE; return *status; } assert(entry->object.symlink); PTHREAD_RWLOCK_RDLOCK(&entry->content_lock); if (!(entry->flags & CACHE_INODE_TRUST_CONTENT)) { /* Our data are stale. Drop the lock, get a write-lock, load in new data, and copy it out to the caller. */ PTHREAD_RWLOCK_UNLOCK(&entry->content_lock); PTHREAD_RWLOCK_WRLOCK(&entry->content_lock); /* Make sure nobody updated the content while we were waiting. */ if (!(entry->flags & CACHE_INODE_TRUST_CONTENT)) { fsal_status = FSAL_readlink(&entry->handle, context, &entry->object.symlink->content, NULL); if (!(FSAL_IS_ERROR(fsal_status))) { atomic_set_uint32_t_bits(&entry->flags, CACHE_INODE_TRUST_CONTENT); } } } if (!(FSAL_IS_ERROR(fsal_status))) { FSAL_pathcpy(link_content, &(entry->object.symlink->content)); } PTHREAD_RWLOCK_UNLOCK(&entry->content_lock); if (FSAL_IS_ERROR(fsal_status)) { *status = cache_inode_error_convert(fsal_status); if (fsal_status.major == ERR_FSAL_STALE) { LogEvent(COMPONENT_CACHE_INODE, "FSAL returned STALE from readlink"); cache_inode_kill_entry(entry); } return *status; } return *status; } /* cache_inode_readlink */
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 */
fsal_status_t LUSTREFSAL_rename(lustrefsal_handle_t * p_old_parentdir_handle, /* IN */ fsal_name_t * p_old_name, /* IN */ lustrefsal_handle_t * p_new_parentdir_handle, /* IN */ fsal_name_t * p_new_name, /* IN */ lustrefsal_op_context_t * p_context, /* IN */ fsal_attrib_list_t * p_src_dir_attributes, /* [ IN/OUT ] */ fsal_attrib_list_t * p_tgt_dir_attributes /* [ IN/OUT ] */ ) { int rc, errsv; fsal_status_t status; struct stat old_parent_buffstat, new_parent_buffstat, buffstat; fsal_path_t old_fsalpath, new_fsalpath; int src_equal_tgt = FALSE; /* sanity checks. * note : src/tgt_dir_attributes are optional. */ if(!p_old_parentdir_handle || !p_new_parentdir_handle || !p_old_name || !p_new_name || !p_context) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_rename); /* Get directory access path by fid */ status = fsal_internal_Handle2FidPath(p_context, p_old_parentdir_handle, &old_fsalpath); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_rename); /* retrieve directory metadata for checking access rights */ TakeTokenFSCall(); rc = lstat(old_fsalpath.path, &old_parent_buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) { if(errsv == ENOENT) Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_rename); else Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rename); } /* optimisation : don't do the job twice if source dir = dest dir */ if(!LUSTREFSAL_handlecmp(p_old_parentdir_handle, p_new_parentdir_handle, &status)) { FSAL_pathcpy(&new_fsalpath, &old_fsalpath); src_equal_tgt = TRUE; new_parent_buffstat = old_parent_buffstat; } else { status = fsal_internal_Handle2FidPath(p_context, p_new_parentdir_handle, &new_fsalpath); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_rename); /* retrieve destination attrs */ TakeTokenFSCall(); rc = lstat(new_fsalpath.path, &new_parent_buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) { if(errsv == ENOENT) Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_rename); else Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rename); } } /* check access rights */ status = fsal_internal_testAccess(p_context, FSAL_W_OK | FSAL_X_OK, &old_parent_buffstat, NULL); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_rename); if(!src_equal_tgt) { status = fsal_internal_testAccess(p_context, FSAL_W_OK | FSAL_X_OK, &new_parent_buffstat, NULL); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_rename); } /* build file paths */ status = fsal_internal_appendNameToPath(&old_fsalpath, p_old_name); if(FSAL_IS_ERROR(status)) Return(status.major, status.minor, INDEX_FSAL_rename); status = fsal_internal_appendNameToPath(&new_fsalpath, p_new_name); if(FSAL_IS_ERROR(status)) Return(status.major, status.minor, INDEX_FSAL_rename); TakeTokenFSCall(); rc = lstat(old_fsalpath.path, &buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rename); /* Check sticky bits */ /* Sticky bit on the source directory => the user who wants to delete the file must own it or its parent dir */ if((old_parent_buffstat.st_mode & S_ISVTX) && old_parent_buffstat.st_uid != p_context->credential.user && buffstat.st_uid != p_context->credential.user && p_context->credential.user != 0) Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_rename); /* Sticky bit on the target directory => the user who wants to create the file must own it or its parent dir */ if(new_parent_buffstat.st_mode & S_ISVTX) { TakeTokenFSCall(); rc = lstat(new_fsalpath.path, &buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) { if(errsv != ENOENT) Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rename); } else if(new_parent_buffstat.st_uid != p_context->credential.user && buffstat.st_uid != p_context->credential.user && p_context->credential.user != 0) Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_rename); } /************************************* * Rename the file on the filesystem * *************************************/ TakeTokenFSCall(); rc = rename(old_fsalpath.path, new_fsalpath.path); errsv = errno; ReleaseTokenFSCall(); if(rc) Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rename); /*********************** * Fill the attributes * ***********************/ if(p_src_dir_attributes) { status = LUSTREFSAL_getattrs(p_old_parentdir_handle, p_context, p_src_dir_attributes); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_src_dir_attributes->asked_attributes); FSAL_SET_MASK(p_src_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } if(p_tgt_dir_attributes) { status = LUSTREFSAL_getattrs(p_new_parentdir_handle, p_context, p_tgt_dir_attributes); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_tgt_dir_attributes->asked_attributes); FSAL_SET_MASK(p_tgt_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_rename); }
/** * Get a valid path associated to an handle. * The function selects many paths from the DB and return the first valid one. If is_dir is set, then only 1 path will be constructed from the database. */ fsal_status_t fsal_internal_getPathFromHandle(posixfsal_op_context_t * p_context, /* IN */ posixfsal_handle_t * p_handle, /* IN */ int is_dir, /* IN */ fsal_path_t * p_fsalpath, /* OUT */ struct stat *p_buffstat /* OUT */ ) { fsal_status_t status; fsal_posixdb_status_t statusdb; int rc, errsv, count, i; fsal_posixdb_fileinfo_t infofs; fsal_path_t paths[global_fs_info.maxlink]; if(!p_context || !p_handle || !p_fsalpath) ReturnCode(ERR_FSAL_FAULT, 0); /* if there is a path in the posixfsal_handle_t variable, then try to use it instead of querying the database for it */ /* Read the path from the Handle. If it's valid & coherent, then no need to query the database ! */ /* if !p_buffstat, we don't need to check the path */ statusdb = fsal_posixdb_getInfoFromHandle(p_context->p_conn, p_handle, paths, (is_dir ? 1 : global_fs_info.maxlink), &count); if(FSAL_POSIXDB_IS_ERROR(statusdb) && FSAL_IS_ERROR(status = posixdb2fsal_error(statusdb))) return status; /* if !p_buffstat, then we do not stat the path to test if file is valid */ if(p_buffstat) { for(i = 0; i < count; i++) { TakeTokenFSCall(); rc = lstat(paths[i].path, p_buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) { /* error : delete the bad path from the database */ char dirc[FSAL_MAX_PATH_LEN]; char basec[FSAL_MAX_PATH_LEN]; fsal_path_t parentdir; fsal_name_t filename; posixfsal_handle_t parenthdl; char *dname, *bname; /* split /path/to/filename in /path/to & filename */ strncpy(dirc, paths[i].path, FSAL_MAX_PATH_LEN); strncpy(basec, paths[i].path, FSAL_MAX_PATH_LEN); dname = dirname(dirc); bname = basename(basec); status = FSAL_str2path(dname, FSAL_MAX_PATH_LEN, &parentdir); status = FSAL_str2name(bname, FSAL_MAX_NAME_LEN, &filename); /* get the handle of /path/to */ status = POSIXFSAL_lookupPath(&parentdir, p_context, &parenthdl, NULL); if(!FSAL_IS_ERROR(status)) { statusdb = fsal_posixdb_delete(p_context->p_conn, &parenthdl, &filename, NULL); /* no need to check if there was an error, because it doesn't change the behavior of the function */ } } else { /* no error */ FSAL_pathcpy(p_fsalpath, &(paths[0])); break; } } if(i == count) ReturnCode(ERR_FSAL_STALE, 0); /* check consistency */ status = fsal_internal_posix2posixdb_fileinfo(p_buffstat, &infofs); if(FSAL_IS_ERROR(status)) return status; if(fsal_posixdb_consistency_check(&(p_handle->data.info), &infofs)) { /* not consistent !! */ /* delete the stale handle */ statusdb = fsal_posixdb_deleteHandle(p_context->p_conn, p_handle); if(FSAL_POSIXDB_IS_ERROR(statusdb) && FSAL_IS_ERROR(status = posixdb2fsal_error(statusdb))) return status; ReturnCode(ERR_FSAL_STALE, 0); } } else { /* @TODO : check that there si at liste 1 path */ FSAL_pathcpy(p_fsalpath, &(paths[0])); } ReturnCode(ERR_FSAL_NO_ERROR, 0); }
/** * * cache_inode_renew_entry: Renews the attributes for an entry. * * 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 [OUT] renewed attributes for the entry that we have found. * @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 Other errors shows a FSAL error. * */ cache_inode_status_t cache_inode_renew_entry(cache_entry_t * pentry, 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_handle_t *pfsal_handle = NULL; fsal_status_t fsal_status; fsal_attrib_list_t object_attributes; fsal_path_t link_content; time_t current_time = time(NULL); time_t entry_time = pentry->internal_md.refresh_time; /* If we do nothing (no expiration) then everything is all right */ *pstatus = CACHE_INODE_SUCCESS; if(isFullDebug(COMPONENT_CACHE_INODE)) { char *type; char grace[20], grace2[20]; unsigned int elapsed = (unsigned int)current_time - (unsigned int)entry_time; int print = 1; cache_inode_expire_to_str(pclient->expire_type_attr, pclient->grace_period_attr, grace); switch(pentry->internal_md.type) { case UNASSIGNED: type = "UNASSIGNED"; break; case REGULAR_FILE: type = "REGULAR_FILE"; break; case CHARACTER_FILE: type = "CHARACTER_FILE"; break; case BLOCK_FILE: type = "BLOCK_FILE"; break; case SYMBOLIC_LINK: print = 0; cache_inode_expire_to_str(pclient->expire_type_link, pclient->grace_period_link, grace2); LogDebug(COMPONENT_CACHE_INODE, "Renew Entry test of %p for SYMBOLIC_LINK elapsed time=%u, grace_period_attr=%s, grace_period_link=%s", pentry, elapsed, grace, grace2); break; case SOCKET_FILE: type = "SOCKET_FILE"; break; case FIFO_FILE: type = "FIFO_FILE"; break; case DIRECTORY: print = 0; cache_inode_expire_to_str(pclient->expire_type_dirent, pclient->grace_period_dirent, grace2); LogDebug(COMPONENT_CACHE_INODE, "Renew Entry test of %p for DIRECTORY elapsed time=%u, grace_period_attr=%s, grace_period_dirent=%s, has_been_readdir=%u", pentry, elapsed, grace, grace2, pentry->object.dir.has_been_readdir); break; case FS_JUNCTION: type = "FS_JUNCTION"; break; case RECYCLED: type = "RECYCLED"; break; default: type = "UNKNOWN"; break; } if(print) { LogDebug(COMPONENT_CACHE_INODE, "Renew Entry test of %p for %s elapsed time=%u, grace_period_attr=%s", pentry, type, elapsed, grace); } } /* An entry that is a regular file with an associated File Content Entry won't * expire until data exists in File Content Cache, to avoid attributes incoherency */ /* @todo: BUGAZOMEU: I got serious doubts on the following blocks: possible trouble if using data caching */ if(pentry->internal_md.type == REGULAR_FILE && pentry->object.file.pentry_content != NULL) { /* Successfull exit without having nothing to do ... */ LogDebug(COMPONENT_CACHE_INODE, "Entry %p is a REGULAR_FILE with associated data cached %p, no expiration", pentry, pentry->object.file.pentry_content); *pstatus = CACHE_INODE_SUCCESS; return *pstatus; } LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry use getattr/mtime checking %d, is dir " "beginning %d, has bit in mask %d, has been readdir %d state %d", pclient->getattr_dir_invalidation, pentry->internal_md.type == DIRECTORY, (int) FSAL_TEST_MASK(pclient->attrmask, FSAL_ATTR_MTIME), pentry->object.dir.has_been_readdir, pentry->internal_md.valid_state); /* Do we use getattr/mtime checking */ if(pclient->getattr_dir_invalidation && pentry->internal_md.type == DIRECTORY && FSAL_TEST_MASK(pclient->attrmask, FSAL_ATTR_MTIME) /*&& pentry->object.dir.has_been_readdir == CACHE_INODE_YES*/) { /* This checking is to be done ... */ LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry testing directory mtime"); pfsal_handle = &pentry->object.dir.handle; /* Call FSAL to get the attributes */ object_attributes.asked_attributes = pclient->attrmask; fsal_status = FSAL_getattrs(pfsal_handle, pcontext, &object_attributes); if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); if(fsal_status.major == ERR_FSAL_STALE) { cache_inode_status_t kill_status; LogEvent(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: Stale FSAL File Handle detected for pentry = %p, line %u, fsal_status=(%u,%u)", pentry, __LINE__, 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_renew_entry: 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_RENEW_ENTRY])++; LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: returning %d (%s) from FSAL_getattrs for getattr/mtime checking", *pstatus, cache_inode_err_str(*pstatus)); return *pstatus; } LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: Entry=%p, type=%d, Cached Time=%d, FSAL Time=%d", pentry, pentry->internal_md.type, pentry->object.dir.attributes.mtime.seconds, object_attributes.mtime.seconds); /* Compare the FSAL mtime and the cached mtime */ if(pentry->object.dir.attributes.mtime.seconds < object_attributes.mtime.seconds) { /* Cached directory content is obsolete, it must be renewed */ cache_inode_set_attributes(pentry, &object_attributes); /* Return the attributes as set */ if(pattr != NULL) *pattr = object_attributes; /* Set the directory content as "to be renewed" */ /* Next call to cache_inode_readdir will repopulate the dirent array */ pentry->object.dir.has_been_readdir = CACHE_INODE_RENEW_NEEDED; /* Set the refresh time for the cache entry */ pentry->internal_md.refresh_time = time(NULL); LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: cached directory content for entry %p must be renewed, due to getattr mismatch", pentry); if(cache_inode_invalidate_all_cached_dirent(pentry, ht, pclient, pstatus) != CACHE_INODE_SUCCESS) { /* Should never happen */ LogCrit(COMPONENT_CACHE_INODE, "cache_inode_invalidate_all_cached_dirent returned %d (%s)", *pstatus, cache_inode_err_str(*pstatus)); return *pstatus; } } /* if( pentry->object.dir.attributes.mtime < object_attributes.asked_attributes.mtime ) */ } /* if( pclient->getattr_dir_invalidation && ... */ /* Check for dir content expiration and/or staleness */ if(pentry->internal_md.type == DIRECTORY && pclient->expire_type_dirent != CACHE_INODE_EXPIRE_NEVER && pentry->object.dir.has_been_readdir == CACHE_INODE_YES && ((current_time - entry_time >= pclient->grace_period_dirent) || (pentry->internal_md.valid_state == STALE))) { /* Would be better if state was a flag that we could and/or the bits but * in any case we need to get rid of stale so we only go through here * once. */ if ( pentry->internal_md.valid_state == STALE ) pentry->internal_md.valid_state = VALID; /* stats */ (pclient->stat.func_stats.nb_call[CACHE_INODE_RENEW_ENTRY])++; /* Log */ LogDebug(COMPONENT_CACHE_INODE, "Case 1: cached directory entries for entry %p must be renewed" " (has been readdir)", pentry); if(isFullDebug(COMPONENT_CACHE_INODE)) { char name[1024]; struct avltree_node *d_node; cache_inode_dir_entry_t *d_dirent; int i = 0; d_node = avltree_first(&pentry->object.dir.dentries); do { d_dirent = avltree_container_of(d_node, cache_inode_dir_entry_t, node_n); if (d_dirent->pentry->internal_md.valid_state == VALID) { FSAL_name2str(&(d_dirent->name), name, 1023); LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: Entry %d %s", i, name); } i++; } while ((d_node = avltree_next(d_node))); } /* Do the getattr if it had not being done before */ if(pfsal_handle == NULL) { pfsal_handle = &pentry->object.dir.handle; /* Call FSAL to get the attributes */ object_attributes.asked_attributes = pclient->attrmask; fsal_status = FSAL_getattrs(pfsal_handle, pcontext, &object_attributes); if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); /* stats */ (pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_RENEW_ENTRY])++; if(fsal_status.major == ERR_FSAL_STALE) { cache_inode_status_t kill_status; LogEvent(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: Stale FSAL File Handle detected for pentry = %p, line %u, fsal_status=(%u,%u)", pentry, __LINE__,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_renew_entry: Could not kill entry %p, status = %u", pentry, kill_status); *pstatus = CACHE_INODE_FSAL_ESTALE; } LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry returning %d (%s) from FSAL_getattrs for directory entries (1)", *pstatus, cache_inode_err_str(*pstatus)); return *pstatus; } } cache_inode_set_attributes(pentry, &object_attributes); /* Return the attributes as set */ if(pattr != NULL) *pattr = object_attributes; /* Set the directory content as "to be renewed" */ /* Next call to cache_inode_readdir will repopulate the dirent array */ pentry->object.dir.has_been_readdir = CACHE_INODE_RENEW_NEEDED; /* Set the refresh time for the cache entry */ pentry->internal_md.refresh_time = time(NULL); } /* if( pentry->internal_md.type == DIRECTORY && ... */ /* if the directory has not been readdir, only update its attributes */ else if(pentry->internal_md.type == DIRECTORY && pclient->expire_type_attr != CACHE_INODE_EXPIRE_NEVER && pentry->object.dir.has_been_readdir != CACHE_INODE_YES && ((current_time - entry_time >= pclient->grace_period_attr) || (pentry->internal_md.valid_state == STALE))) { /* Would be better if state was a flag that we could and/or the bits but * in any case we need to get rid of stale so we only go through here * once. */ if ( pentry->internal_md.valid_state == STALE ) pentry->internal_md.valid_state = VALID; /* stats */ (pclient->stat.func_stats.nb_call[CACHE_INODE_RENEW_ENTRY])++; /* Log */ LogDebug(COMPONENT_CACHE_INODE, "Case 2: cached directory entries for entry %p must be renewed (has not been readdir)", pentry); if(isFullDebug(COMPONENT_CACHE_INODE)) { char name[1024]; struct avltree_node *d_node; cache_inode_dir_entry_t *d_dirent; int i = 0; d_node = avltree_first(&pentry->object.dir.dentries); do { d_dirent = avltree_container_of(d_node, cache_inode_dir_entry_t, node_n); if (d_dirent->pentry->internal_md.valid_state == VALID) { FSAL_name2str(&(d_dirent->name), name, 1023); LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: Entry %d %s", i, name); } i++; } while ((d_node = avltree_next(d_node))); } pfsal_handle = &pentry->object.dir.handle; /* Call FSAL to get the attributes */ object_attributes.asked_attributes = pclient->attrmask; fsal_status = FSAL_getattrs(pfsal_handle, pcontext, &object_attributes); if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); /* stats */ (pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_RENEW_ENTRY])++; if(fsal_status.major == ERR_FSAL_STALE) { cache_inode_status_t kill_status; LogEvent(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: Stale FSAL File Handle detected for pentry = %p, line %u, fsal_status=(%u,%u)", pentry, __LINE__,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_renew_entry: Could not kill entry %p, status = %u", pentry, kill_status); *pstatus = CACHE_INODE_FSAL_ESTALE; } LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry returning %d (%s) from FSAL_getattrs for directory entries (2)", *pstatus, cache_inode_err_str(*pstatus)); return *pstatus; } cache_inode_set_attributes(pentry, &object_attributes); /* Return the attributes as set */ if(pattr != NULL) *pattr = object_attributes; /* Set the refresh time for the cache entry */ pentry->internal_md.refresh_time = time(NULL); } /* else if( pentry->internal_md.type == DIRECTORY && ... */ /* Check for attributes expiration in other cases */ else if(pentry->internal_md.type != DIRECTORY && pclient->expire_type_attr != CACHE_INODE_EXPIRE_NEVER && ((current_time - entry_time >= pclient->grace_period_attr) || (pentry->internal_md.valid_state == STALE))) { /* Would be better if state was a flag that we could and/or the bits but * in any case we need to get rid of stale so we only go through here * once. */ if ( pentry->internal_md.valid_state == STALE ) pentry->internal_md.valid_state = VALID; /* stats */ (pclient->stat.func_stats.nb_call[CACHE_INODE_RENEW_ENTRY])++; /* Log */ LogDebug(COMPONENT_CACHE_INODE, "Attributes for entry %p must be renewed", pentry); 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 SOCKET_FILE: case FIFO_FILE: case CHARACTER_FILE: case BLOCK_FILE: pfsal_handle = &pentry->object.special_obj.handle; break; case DIRECTORY: case FS_JUNCTION: 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 get the attributes */ object_attributes.asked_attributes = pclient->attrmask; #ifdef _USE_MFSL fsal_status = FSAL_getattrs_descriptor(&(cache_inode_fd(pentry)->fsal_file), pfsal_handle, pcontext, &object_attributes); #else fsal_status = FSAL_getattrs_descriptor(cache_inode_fd(pentry), pfsal_handle, pcontext, &object_attributes); #endif if(FSAL_IS_ERROR(fsal_status) && fsal_status.major == ERR_FSAL_NOT_OPENED) { //TODO: LOOKATME !!!!! fsal_status = FSAL_getattrs(pfsal_handle, pcontext, &object_attributes); } if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); /* stats */ (pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_RENEW_ENTRY])++; if(fsal_status.major == ERR_FSAL_STALE) { cache_inode_status_t kill_status; LogEvent(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: Stale FSAL File Handle detected for pentry = %p, line %u, fsal_status=(%u,%u)", pentry, __LINE__,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_renew_entry: Could not kill entry %p, status = %u", pentry, kill_status); *pstatus = CACHE_INODE_FSAL_ESTALE; } LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry returning %d (%s) from FSAL_getattrs for non directories", *pstatus, cache_inode_err_str(*pstatus)); return *pstatus; } /* Keep the new attribute in cache */ cache_inode_set_attributes(pentry, &object_attributes); /* Return the attributes as set */ if(pattr != NULL) *pattr = object_attributes; /* Set the refresh time for the cache entry */ pentry->internal_md.refresh_time = time(NULL); } /* if( pentry->internal_md.type != DIR_CONTINUE && ... */ /* Check for link content expiration */ if(pentry->internal_md.type == SYMBOLIC_LINK && pclient->expire_type_link != CACHE_INODE_EXPIRE_NEVER && ((current_time - entry_time >= pclient->grace_period_link) || (pentry->internal_md.valid_state == STALE))) { assert(pentry->object.symlink); pfsal_handle = &pentry->object.symlink->handle; /* Would be better if state was a flag that we could and/or the bits but * in any case we need to get rid of stale so we only go through here * once. */ if ( pentry->internal_md.valid_state == STALE ) pentry->internal_md.valid_state = VALID; assert(pentry->object.symlink); pfsal_handle = &pentry->object.symlink->handle; /* Log */ LogDebug(COMPONENT_CACHE_INODE, "cached link content for entry %p must be renewed", pentry); FSAL_CLEAR_MASK(object_attributes.asked_attributes); FSAL_SET_MASK(object_attributes.asked_attributes, pclient->attrmask); if( CACHE_INODE_KEEP_CONTENT( pentry->policy ) ) { #ifdef _USE_MFSL fsal_status = MFSL_readlink(&pentry->mobject, pcontext, &pclient->mfsl_context, &link_content, &object_attributes, NULL); #else fsal_status = FSAL_readlink(pfsal_handle, pcontext, &link_content, &object_attributes); #endif } else { fsal_status.major = ERR_FSAL_NO_ERROR ; fsal_status.minor = 0 ; } if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); /* stats */ pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_RENEW_ENTRY] += 1; if(fsal_status.major == ERR_FSAL_STALE) { cache_inode_status_t kill_status; LogEvent(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: Stale FSAL File Handle detected for pentry = %p, line %u, fsal_status=(%u,%u)", pentry, __LINE__,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_renew_entry: Could not kill entry %p, status = %u", pentry, kill_status); *pstatus = CACHE_INODE_FSAL_ESTALE; } } else { assert(pentry->object.symlink); fsal_status = FSAL_pathcpy(&pentry->object.symlink->content, &link_content); /* copy ctor? */ if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); /* stats */ pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_RENEW_ENTRY] += 1; } } /* Set the refresh time for the cache entry */ pentry->internal_md.refresh_time = time(NULL); } /* if( pentry->internal_md.type == SYMBOLIC_LINK && ... */ LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry returning %d (%s)", *pstatus, cache_inode_err_str(*pstatus)); return *pstatus; } /* cache_inode_renew_entry */