/** * * cache_inode_is_dir_empty_WithLock: checks if a directory is empty or not, BUT has lock management. * * Checks if a directory is empty or not, BUT has lock management. * * @param pentry [IN] entry to be checked (should be of type DIRECTORY) * * @return CACHE_INODE_SUCCESS is directory is empty\n * @return CACHE_INODE_BAD_TYPE is pentry is not of type DIRECTORY\n * @return CACHE_INODE_DIR_NOT_EMPTY if pentry is not empty * */ cache_inode_status_t cache_inode_is_dir_empty_WithLock(cache_entry_t * pentry) { cache_inode_status_t status; P_r(&pentry->lock); status = cache_inode_is_dir_empty(pentry); V_r(&pentry->lock); return status; } /* cache_inode_is_dir_empty_WithLock */
cache_inode_status_t cache_inode_is_dir_empty_WithLock(cache_entry_t *entry) { cache_inode_status_t status; pthread_rwlock_rdlock(&entry->content_lock); status = cache_inode_is_dir_empty(entry); pthread_rwlock_unlock(&entry->content_lock); return status; } /* cache_inode_is_dir_empty_WithLock */
/** * * 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 */
/** * * 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 */