static bool disk_scan_latency_stride(disk_t *disk, struct scan_state *state, uint64_t base_offset, uint64_t data_size, uint32_t *scan_order) { unsigned i; uint64_t stride_end = base_offset + state->latency_stride * disk->sector_size; if (stride_end > disk->num_bytes) stride_end = disk->num_bytes; for (i = 0; disk->run && scan_order[i] != UINT32_MAX; i++) { uint64_t offset = base_offset + scan_order[i]; progress_calc(disk, state, data_size); VVVERBOSE("Scanning at offset %"PRIu64" index %u", offset, i); int64_t remainder = stride_end - offset; if (remainder < (int64_t)data_size) { data_size = remainder; VERBOSE("Last part scanning size %"PRIu64, data_size); } if (offset > disk->num_bytes || (offset+remainder) > disk->num_bytes) continue; if (!disk_scan_part(disk, offset, state->data, data_size, state)) return false; } return true; }
static void print_header(void) { printf("diskscan version %s\n\n", VERSION); VERBOSE("Verbosity set"); VVERBOSE("High verbosity set"); VVVERBOSE("Very high verbosity set"); }
int disk_scan(disk_t *disk, enum scan_mode mode, unsigned data_size) { disk->run = 1; void *data = allocate_buffer(data_size); uint32_t *scan_order = NULL; int result = 0; struct scan_state state = {.latency = NULL, .progress_bytes = 0, .progress_full = 1000}; struct timespec ts_start; struct timespec ts_end; time_t scan_time; disk->conclusion = CONCLUSION_SCAN_PROBLEM; if (data_size % disk->sector_size != 0) { data_size -= data_size % disk->sector_size; if (data_size == 0) data_size = disk->sector_size; ERROR("Cannot scan data not in multiples of the sector size, adjusted scan size to %u", data_size); } set_realtime(true); clock_gettime(CLOCK_MONOTONIC, &ts_start); INFO("Scanning disk %s in %u byte steps", disk->path, data_size); scan_time = time(NULL); INFO("Scan started at: %s", ctime(&scan_time)); VVVERBOSE("Using buffer of size %d", data_size); if (data == NULL) { ERROR("Failed to allocate data buffer, errno=%d: %s", errno, strerror(errno)); result = 1; goto Exit; } uint64_t offset; const uint64_t disk_size_bytes = disk->num_bytes; const uint64_t latency_stride = calc_latency_stride(disk); VVERBOSE("latency stride is %"PRIu64, latency_stride); state.latency_bucket = 0; state.latency_stride = latency_stride; state.latency_count = 0; state.latency = malloc(sizeof(uint32_t) * latency_stride); state.data = data; scan_order = calc_scan_order(disk, mode, latency_stride, data_size); if (!scan_order) { result = 1; ERROR("Failed to generate scan order"); goto Exit; } verbose_extra_newline = 1; for (offset = 0; disk->run && offset < disk_size_bytes; offset += latency_stride * disk->sector_size) { VERBOSE("Scanning stride starting at %"PRIu64" done %"PRIu64"%%", offset, offset*100/disk_size_bytes); progress_calc(disk, &state, 0); latency_bucket_prepare(disk, &state, offset); if (!disk_scan_latency_stride(disk, &state, offset, data_size, scan_order)) break; latency_bucket_finish(disk, &state, offset + latency_stride * disk->sector_size); if (disk->is_ata) disk_ata_monitor(disk); else disk_scsi_monitor(disk); } verbose_extra_newline = 0; if (!disk->run) { INFO("Disk scan interrupted"); disk->conclusion = CONCLUSION_ABORTED; } else { disk->conclusion = conclusion_calc(disk); } report_scan_done(disk); Exit: clock_gettime(CLOCK_MONOTONIC, &ts_end); set_realtime(false); free(scan_order); free_buffer(data, data_size); free(state.latency); disk->run = 0; scan_time = time(NULL); INFO("Scan ended at: %s", ctime(&scan_time)); INFO("Scan took %d second", (int)(ts_end.tv_sec - ts_start.tv_sec)); return result; }