/** * * cache_content_crash_recover: recovers the data cache and the associated inode after a crash. * * @param pclient [IN] ressource allocated by the client for the nfs management. * @pstatus [OUT] returned status. * * @return CACHE_CONTENT_SUCCESS is successful. * */ cache_content_status_t cache_content_crash_recover(unsigned short exportid, unsigned int index, unsigned int mod, cache_content_client_t * pclient_data, cache_inode_client_t * pclient_inode, hash_table_t * ht, fsal_op_context_t * pcontext, cache_content_status_t * pstatus) { DIR *cache_directory; cache_content_dirinfo_t export_directory; char cache_exportdir[MAXPATHLEN]; char fullpath[MAXPATHLEN]; struct dirent *direntp; struct dirent dirent_export; int found_export_id; u_int64_t inum; off_t size_in_cache; cache_entry_t inode_entry; cache_entry_t *pentry = NULL; cache_content_entry_t *pentry_content = NULL; cache_inode_status_t cache_inode_status; cache_content_status_t cache_content_status; fsal_attrib_list_t fsal_attr; cache_inode_fsal_data_t fsal_data; *pstatus = CACHE_CONTENT_SUCCESS; /* Open the cache directory */ if((cache_directory = opendir(pclient_data->cache_dir)) == NULL) { *pstatus = CACHE_CONTENT_LOCAL_CACHE_ERROR; return *pstatus; } /* read the cache directory */ while((direntp = readdir(cache_directory)) != NULL) { /* . and .. are of no interest */ if(!strcmp(direntp->d_name, ".") || !strcmp(direntp->d_name, "..")) continue; if((found_export_id = cache_content_get_export_id(direntp->d_name)) >= 0) { LogEvent(COMPONENT_CACHE_CONTENT, "Directory cache for Export ID %d has been found", found_export_id); snprintf(cache_exportdir, MAXPATHLEN, "%s/%s", pclient_data->cache_dir, direntp->d_name); if(cache_content_local_cache_opendir(cache_exportdir, &(export_directory)) == FALSE) { *pstatus = CACHE_CONTENT_LOCAL_CACHE_ERROR; closedir(cache_directory); return *pstatus; } /* Reads the directory content (a single thread for the moment) */ while(cache_content_local_cache_dir_iter (&export_directory, &dirent_export, index, mod)) { /* . and .. are of no interest */ if(!strcmp(dirent_export.d_name, ".") || !strcmp(dirent_export.d_name, "..")) continue; if((inum = cache_content_get_inum(dirent_export.d_name)) > 0) { LogEvent(COMPONENT_CACHE_CONTENT, "Cache entry for File ID %llx has been found", inum); /* Get the content of the file */ sprintf(fullpath, "%s/%s/%s", pclient_data->cache_dir, direntp->d_name, dirent_export.d_name); if((cache_inode_status = cache_inode_reload_content(fullpath, &inode_entry)) != CACHE_INODE_SUCCESS) { LogMajor(COMPONENT_CACHE_CONTENT, "File Content Cache record for File ID %llx is unreadable", inum); continue; } else LogMajor(COMPONENT_CACHE_CONTENT, "File Content Cache record for File ID %llx : READ OK", inum); /* Populating the cache_inode... */ fsal_data.handle = inode_entry.object.file.handle; fsal_data.cookie = 0; if((pentry = cache_inode_get(&fsal_data, &fsal_attr, ht, pclient_inode, pcontext, &cache_inode_status)) == NULL) { LogCrit(COMPONENT_CACHE_CONTENT, "Error adding cached inode for file ID %llx, error=%d", inum, cache_inode_status); continue; } else LogEvent(COMPONENT_CACHE_CONTENT, "Cached inode added successfully for file ID %llx", inum); /* Get the size from the cache */ if((size_in_cache = cache_content_recover_size(cache_exportdir, inum)) == -1) { LogCrit(COMPONENT_CACHE_CONTENT, "Error when recovering size for file ID %llx", inum); } else pentry->object.file.attributes.filesize = (fsal_size_t) size_in_cache; /* Adding the cached entry to the data cache */ if((pentry_content = cache_content_new_entry(pentry, NULL, pclient_data, RECOVER_ENTRY, pcontext, &cache_content_status)) == NULL) { LogCrit(COMPONENT_CACHE_CONTENT, "Error adding cached data for file ID %llx, error=%d", inum, cache_inode_status); continue; } else LogEvent(COMPONENT_CACHE_CONTENT, "Cached data added successfully for file ID %llx", inum); if((cache_content_status = cache_content_valid(pentry_content, CACHE_CONTENT_OP_GET, pclient_data)) != CACHE_CONTENT_SUCCESS) { *pstatus = cache_content_status; return *pstatus; } } } /* while( ( dirent_export = readdir( export_directory ) ) != NULL ) */ /* Close the export cache directory */ cache_content_local_cache_closedir(&export_directory); } /* if( ( found_export_id = cache_content_get_export_id( direntp->d_name ) ) > 0 ) */ } /* while( ( direntp = readdir( cache_directory ) ) != NULL ) */ /* Close the cache directory */ closedir(cache_directory); return *pstatus; } /* cache_content_crash_recover */
/** * * cache_content_rdwr: Reads/Writes through the cache layer. * * Reads/Writes through the cache layer. * This routine should be called only from the cache_inode layer. * * No lock management is done in this layer: the related pentry in the cache inode layer is * locked and will prevent from concurent accesses. * * @param pentry [IN] entry in file content layer whose content is to be accessed. * @param read_or_write [IN] a flag of type cache_content_io_direction_t to tell if a read or write is to be done. * @param seek_descriptor [IN] absolute position (in the FSAL file) where the IO will be done. * @param pio_size_in [IN] requested io size * @param pio_size_out [OUT] the size of the io that was successfully made. * @param pbuffstat [OUT] the 'stat' of entry in the data cache after the operation * @param buffer write:[IN] read:[OUT] the buffer for the data. * @param pclient [IN] ressource allocated by the client for the nfs management. * @param pcontext [IN] fsal credentials for the operation. * @pstatus [OUT] returned status. * * @return CACHE_CONTENT_SUCCESS is successful . * */ cache_content_status_t cache_content_rdwr(cache_content_entry_t * pentry, cache_content_io_direction_t read_or_write, fsal_seek_t * seek_descriptor, fsal_size_t * pio_size_in, fsal_size_t * pio_size_out, caddr_t buffer, fsal_boolean_t * p_fsal_eof, struct stat * pbuffstat, cache_content_client_t * pclient, fsal_op_context_t * pcontext, cache_content_status_t * pstatus) { fsal_handle_t *pfsal_handle = NULL; fsal_status_t fsal_status; cache_inode_status_t cache_inode_status; cache_content_status_t cache_content_status; fsal_path_t local_path; int statindex; off_t offset; size_t iosize_before; ssize_t iosize_after; struct stat buffstat; int rc; char c; *pstatus = CACHE_CONTENT_SUCCESS; LogFullDebug(COMPONENT_CACHE_CONTENT, "---> DATA : IO Size IN = %llu fdsize=%zu seeksize=%zu", *pio_size_in, sizeof(fsal_file_t), sizeof(fsal_seek_t)); /* For now, only FSAL_SEEK_SET is supported */ if(seek_descriptor->whence != FSAL_SEEK_SET) { LogDebug(COMPONENT_CACHE_CONTENT, "Implementation trouble: seek_descriptor was not a 'FSAL_SEEK_SET' cursor"); *pstatus = CACHE_INODE_INVALID_ARGUMENT; return *pstatus; } /* Set the statindex variable */ switch (read_or_write) { case CACHE_CONTENT_READ: statindex = CACHE_CONTENT_READ_ENTRY; break; case CACHE_CONTENT_WRITE: statindex = CACHE_CONTENT_WRITE_ENTRY; break; default: *pstatus = CACHE_CONTENT_INVALID_ARGUMENT; return *pstatus; break; } /* stat */ pclient->stat.func_stats.nb_call[statindex] += 1; /* Get the fsal handle */ if((pfsal_handle = cache_inode_get_fsal_handle(pentry->pentry_inode, &cache_inode_status)) == NULL) { *pstatus = CACHE_CONTENT_BAD_CACHE_INODE_ENTRY; LogMajor(COMPONENT_CACHE_CONTENT, "cache_content_rdwr: cannot get handle"); /* stat */ pclient->stat.func_stats.nb_err_unrecover[statindex] += 1; return *pstatus; } /* Convert the path to FSAL path */ fsal_status = FSAL_str2path(pentry->local_fs_entry.cache_path_data, MAXPATHLEN, &local_path); if(FSAL_IS_ERROR(fsal_status)) { *pstatus = CACHE_CONTENT_FSAL_ERROR; /* stat */ pclient->stat.func_stats.nb_err_unrecover[statindex] += 1; return *pstatus; } /* Parameters conversion */ offset = cache_content_fsal_seek_convert(*seek_descriptor, pstatus); if(*pstatus != CACHE_CONTENT_SUCCESS) { /* stat */ pclient->stat.func_stats.nb_err_unrecover[statindex] += 1; return *pstatus; } iosize_before = cache_content_fsal_size_convert(*pio_size_in, pstatus); if(*pstatus != CACHE_CONTENT_SUCCESS) { /* stat */ pclient->stat.func_stats.nb_err_unrecover[statindex] += 1; return *pstatus; } /* Open the local fd for reading */ if(cache_content_open(pentry, pclient, pstatus) != CACHE_CONTENT_SUCCESS) { return *pstatus; } /* Perform the IO through the cache */ if(read_or_write == CACHE_CONTENT_READ) { /* The file content was completely read before the IO. The read operation is fully done locally */ if((iosize_after = pread(pentry->local_fs_entry.opened_file.local_fd, buffer, iosize_before, offset)) == -1) { /* stat */ pclient->stat.func_stats.nb_err_unrecover[statindex] += 1; *pstatus = CACHE_CONTENT_LOCAL_CACHE_ERROR; return *pstatus; } if((cache_content_status = cache_content_valid(pentry, CACHE_CONTENT_OP_GET, pclient)) != CACHE_CONTENT_SUCCESS) { *pstatus = cache_content_status; return *pstatus; } /* Get the eof */ if(iosize_after == 0) *p_fsal_eof = TRUE; else { rc = pread(pentry->local_fs_entry.opened_file.local_fd, &c, 1, offset + iosize_before); if(rc == 0) *p_fsal_eof = TRUE; else *p_fsal_eof = FALSE; } } else { /* The io is done on the cache before being flushed to the FSAL */ if((iosize_after = pwrite(pentry->local_fs_entry.opened_file.local_fd, buffer, iosize_before, offset)) == -1) { /* stat */ pclient->stat.func_stats.nb_err_unrecover[statindex] += 1; *pstatus = CACHE_CONTENT_LOCAL_CACHE_ERROR; return *pstatus; } if((cache_content_status = cache_content_valid(pentry, CACHE_CONTENT_OP_SET, pclient)) != CACHE_CONTENT_SUCCESS) { *pstatus = cache_content_status; return *pstatus; } /* p_fsal_eof has no meaning here, it is unused */ } /* close the local fd */ if(cache_content_close(pentry, pclient, pstatus) != CACHE_CONTENT_SUCCESS) return *pstatus; *pio_size_out = (fsal_size_t) iosize_after; /* Return the 'stat' as seen in the cache */ if(stat(pentry->local_fs_entry.cache_path_data, &buffstat) == -1) { *pstatus = CACHE_CONTENT_LOCAL_CACHE_ERROR; } else { if(pbuffstat != NULL) *pbuffstat = buffstat; } return *pstatus; } /* cache_content_rdwr */