2 * Copyright (C) 2004-2005 Jens Axboe <axboe@suse.de>
3 * Copyright (C) 2006 Jens Axboe <axboe@kernel.dk>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
17 #include <sys/types.h>
18 #include <sys/ioctl.h>
24 #if BITS_PER_LONG == 32
25 typedef unsigned long long u64;
26 typedef unsigned long u32;
27 #elif BITS_PER_LONG == 64
28 typedef unsigned long u64;
29 typedef unsigned int u32;
33 #define BLKGETSIZE64 _IOR(0x12,114,size_t)
39 #define ALIGN(buf) (((unsigned long) (buf) + MASK) & ~(MASK))
41 #define BITMAP_BLOCKS(blocks) (((blocks) / BITS_PER_LONG) + 1)
42 #define BITMAP_SIZE(blocks) (BITMAP_BLOCKS(blocks) * sizeof(unsigned long))
44 #define RANDOM_COVERAGE (90)
46 static char device[256];
47 static char state_file[256];
48 static int progress_interval;
49 static int block_size;
50 static int restore_state = 1;
51 static struct timeval start;
52 static int sequential;
53 static int disk_util = 100;
54 static int disk_util_set;
55 static int state_file_fd = -1;
56 static int state_restored;
58 static unsigned long *read_bitmap;
59 static unsigned long find_next_bit_index;
60 static unsigned long blocks_read, blocks_read_now;
63 static struct drand48_data random_state;
71 #define DRIVESCAN_MAGIC 0xabc0ffee
72 #define DRIVESCAN_VERSION 2
74 struct progress_state {
81 struct drand48_data random_state;
84 static inline int test_block_read(unsigned long block)
86 unsigned long index, bitnr;
88 index = block / BITS_PER_LONG;
89 bitnr = block & (BITS_PER_LONG - 1);
90 return (read_bitmap[index] & (1UL << bitnr)) != 0;
93 static inline int mark_block_read(unsigned long block)
95 unsigned long index, bitnr, retval;
97 index = block / BITS_PER_LONG;
98 bitnr = block & (BITS_PER_LONG - 1);
100 retval = (read_bitmap[index] & (1UL << bitnr)) != 0;
101 read_bitmap[index] |= 1UL << bitnr;
105 static inline unsigned long find_next_unread_block(void)
107 unsigned int i, bitnr;
109 for (i = find_next_bit_index; i < BITMAP_BLOCKS(dev_size); i++) {
110 if (read_bitmap[i] == ~0UL)
118 find_next_bit_index = i;
119 bitnr = ffz(read_bitmap[i]);
120 read_bitmap[i] |= 1UL << bitnr;
121 return bitnr + BITS_PER_LONG * i;
124 static int load_progress_state(void)
126 struct progress_state state;
130 if (state_file_fd == -1)
133 if (lseek(state_file_fd, 0, SEEK_SET) == -1) {
134 perror("state file seek");
138 ret = read(state_file_fd, &state, sizeof(state));
140 perror("load progress file");
145 if (state.magic != DRIVESCAN_MAGIC) {
146 printf("Bad magic %lx\n", (unsigned long) state.magic);
149 if (state.version != DRIVESCAN_VERSION) {
150 printf("Unsupported file version (%d)\n", (int) state.version);
153 if (state.arch != ARCH) {
154 printf("State file from different arch\n");
158 read_bitmap = malloc(BITMAP_SIZE(state.blocks));
160 printf("Unable to allocate bitmap (blocks=%Lu)\n", (unsigned long long) state.blocks);
163 memset(read_bitmap, 0, BITMAP_SIZE(dev_size));
165 if (read(state_file_fd, (char *) read_bitmap, BITMAP_SIZE(state.blocks)) < BITMAP_SIZE(state.blocks)) {
166 printf("Unable to read bitmap\n");
171 for (i = 0; i < state.blocks; i++)
172 if (test_block_read(i))
175 if (blocks_read == dev_size)
178 memcpy(&random_state, &state.random_state, sizeof(random_state));
180 dev_size = state.blocks;
181 block_size = state.bs;
183 disk_util = state.disk_util;
184 printf("Restored state: %lu blocks\n", blocks_read);
189 static void save_progress_state(void)
191 struct progress_state state;
194 if (ftruncate(state_file_fd, 0) == -1) {
195 perror("truncate state file");
198 if (lseek(state_file_fd, 0, SEEK_SET) == -1) {
199 perror("lseek state file");
203 memset(&state, 0, sizeof(state));
204 state.magic = DRIVESCAN_MAGIC;
206 state.version = DRIVESCAN_VERSION;
207 state.bs = block_size;
208 state.blocks = dev_size;
209 state.disk_util = disk_util;
210 memcpy(&state.random_state, &random_state, sizeof(random_state));
212 ret = write(state_file_fd, &state, sizeof(state));
214 perror("write state file");
218 ret = write(state_file_fd, (char *) read_bitmap, BITMAP_SIZE(dev_size));
220 perror("write state bitmap");
224 fsync(state_file_fd);
225 printf("Saved state: %lu blocks\n", blocks_read);
228 static unsigned long utime_since(struct timeval *s)
233 gettimeofday(&now, NULL);
234 sec = now.tv_sec - s->tv_sec;
235 usec = now.tv_usec - s->tv_usec;
236 if (sec > 0 && usec < 0) {
240 return usec + (sec * (double) 1000000);
243 static unsigned long time_since_now(void)
245 double sec, usec, ret;
248 gettimeofday(&now, NULL);
249 sec = now.tv_sec - start.tv_sec;
250 usec = now.tv_usec - start.tv_usec;
251 if (sec > 0 && usec < 0) {
255 ret = sec + usec / (double) 1000000;
259 return (unsigned long) ret;
262 static void normalize_time(struct our_time *ot, unsigned long seconds)
264 ot->hour = seconds / 3600;
265 seconds -= ot->hour * 3600;
266 ot->min = seconds / 60;
267 seconds -= ot->min * 60;
271 static void show_progress_state(void)
273 unsigned long rate, now;
274 struct our_time comp, left;
276 now = time_since_now();
278 normalize_time(&comp, now);
283 rate = blocks_read_now / now;
285 memset(&left, 0, sizeof(left));
287 normalize_time(&left, (dev_size * now / blocks_read_now) - now);
290 printf("\tRun: [%luh%lum%lusec, %luh%lum%lusec], %lu blocks/sec, %lu KiB/sec\n", comp.hour, comp.min, comp.sec, left.hour, left.min, left.sec, rate, rate * block_size / 1024);
291 printf("\tRead:[%lu, %lu]: %lu%% coverage\n", blocks_read, (unsigned long) dev_size, (unsigned long) (blocks_read * 100 / dev_size));
294 static void sig_handler(int sig)
296 show_progress_state();
301 save_progress_state();
304 if (progress_interval)
305 alarm(progress_interval);
310 static unsigned long get_next_offset(unsigned long blocks)
312 unsigned long b, retries = dev_size;
318 lrand48_r(&random_state, &r);
319 b = (1+(double) (blocks-1) * r / (RAND_MAX+1.0));
321 if (!mark_block_read(b))
327 printf("Gave up finding new block\n");
333 b = find_next_unread_block();
341 static void idle_drive(struct timeval *s)
343 unsigned long msleep, sleep_time;
346 if (disk_util == 100)
349 msleep = utime_since(s);
350 ratio = (double) 100 / disk_util;
351 sleep_time = msleep * ratio - msleep;
355 static void read_error_report(int fd, char *buffer, unsigned long long offset)
357 unsigned long long bad_block = offset >> 9;
358 int blocks = block_size / 512;
361 if (lseek(fd, offset, SEEK_SET) == -1) {
366 for (i = 0; i < blocks; i++) {
367 ret = read(fd, buffer, 512);
371 else if (ret < 512 && ret >= 0) {
372 printf("Short read at sector %Lu\n", bad_block + i);
375 if (errno == EINVAL) {
376 printf("512-b O_DIRECT does not work\n");
380 printf("Sector %Lu bad\n", bad_block + i);
384 static void do_random_reads(int fd, unsigned long blocks)
390 ptr = malloc(block_size + MASK + 1);
391 buffer = (char *) ALIGN(ptr);
394 off_t offset = get_next_offset(blocks);
397 offset = get_next_offset(blocks);
401 offset = offset * block_size;
403 if (lseek(fd, offset, SEEK_SET) == -1) {
408 gettimeofday(&s, NULL);
409 ret = read(fd, buffer, block_size);
412 if (errno == EINVAL) {
413 printf("EINVAL on read, check if O_DIRECT works\n");
415 } else if (errno == EIO) {
416 read_error_report(fd, buffer, offset);
422 if (ret < block_size)
423 read_error_report(fd, buffer, offset);
425 coverage = blocks_read * 100 / dev_size;
426 if (!sequential && coverage >= RANDOM_COVERAGE) {
427 printf("Switching to scan for rest of blocks\n");
431 if (blocks_read == dev_size)
438 show_progress_state();
443 static int seed_randomizer(void)
448 fd = open("/dev/random", O_RDONLY);
454 if (read(fd, &seed, sizeof(seed)) < (int) sizeof(seed)) {
461 printf("Randomizer seed: %lx\n", seed);
462 srand48_r(seed, &random_state);
466 static void device_to_state_file(void)
468 unsigned int i, offset;
470 offset = sprintf(state_file, "scanstate");
472 for (i = 0; i < strlen(device); i++) {
473 if (device[i] == '/')
474 state_file[offset+i] = '_';
476 state_file[offset+i] = device[i];
480 static void init_state_file(void)
483 device_to_state_file();
485 state_file_fd = open(state_file, O_RDWR | O_CREAT, 0644);
487 if (state_file_fd == -1) {
488 perror("open state file");
493 static int get_options(int argc, char *argv[])
495 static struct option longoptions[] = {
496 { "device", 1, NULL, 'd' },
497 { "block-size", 1, NULL, 'b' },
498 { "progress", 1, NULL, 'p' },
499 { "file", 1, NULL, 'f' },
500 { "restore", 1, NULL, 'r' },
501 { "utilization",1, NULL, 'i' },
505 while ((c = getopt_long(argc, argv, "d:b:p:f:ru:", longoptions, &res)) != -1) {
508 strncpy(device, optarg, sizeof(device) - 1);
511 block_size = atoi(optarg);
512 if (block_size < 1 || block_size > 1024) {
513 printf("bad block size %d\n", block_size);
519 progress_interval = atoi(optarg);
522 strncpy(state_file, optarg, sizeof(state_file)-1);
525 restore_state = !!atoi(optarg);
528 disk_util = atoi(optarg);
539 printf("Must give device with -d\n");
548 int main(int argc, char *argv[])
554 if (get_options(argc, argv))
562 load_progress_state();
564 if (stat(device, &statbuf) == -1) {
569 if (!S_ISBLK(statbuf.st_mode)) {
570 printf("%s does not appear to be a block device\n", device);
574 fd = open(device, O_RDONLY | O_DIRECT | O_LARGEFILE);
580 if (ioctl(fd, BLKGETSIZE64, &size) == -1) {
581 perror("BLKGETSIZE64");
585 blocks = size / block_size;
587 if (state_restored && dev_size != blocks) {
588 printf("Device size seems different %lu != %lu\n", (unsigned long) dev_size, (unsigned long) blocks);
595 read_bitmap = malloc(BITMAP_SIZE(dev_size));
596 memset(read_bitmap, 0, BITMAP_SIZE(dev_size));
599 signal(SIGUSR1, sig_handler);
600 signal(SIGINT, sig_handler);
602 if (progress_interval) {
603 signal(SIGALRM, sig_handler);
604 alarm(progress_interval);
607 gettimeofday(&start, NULL);
608 do_random_reads(fd, blocks);
610 save_progress_state();
612 free((void *) read_bitmap);
614 if (state_file_fd != -1)
615 close(state_file_fd);