* Maximum number of BLOCK_SIZE blocks to read in a single read(2)
*/
#define BLOCK_MULTIPLE 16
+/*
+ * Minimum and maximum number of reads to perform in a single direction before
+ * switching direction
+ */
+#define DIRECTION_MIN 64
+#define DIRECTION_MAX 2048
+
+enum direction {
+ DIR_FORWARD = 0,
+ DIR_BACKWARDS = 1
+};
typedef struct drive_entry {
SLIST_ENTRY(drive_entry) chain;
char *name;
- off_t max, lastpos;
- int lastdir, fd;
+ off_t max, pos;
+ int fd;
+ int dir, dircnt;
} disk_t;
SLIST_HEAD(slisthead, drive_entry);
/* Main loop */
while (run) {
- disk_t *e;
- int blocks;
+ disk_t *e;
+ int blocks;
+ unsigned long diff;
/* Choose a disk */
e = disks_array[random() % ndisks];
blocks = random() % BLOCK_MULTIPLE;
/*
- * Choose a position relative to a previous one and which can
- * withstand the block size
+ * Choose a position relative to a previous one and doesn't
+ * exceed e->max (which already accounts for the block size
+ * and is already BLOCK_SIZE aligned). Our new position must
+ * also be BLOCK_SIZE aligned.
*/
- /* XXX */
+ diff = BALIGN_CEIL(random() % (e->max / DIRECTION_MIN),
+ BLOCK_SIZE);
+ if (e->dir == DIR_BACKWARDS) {
+ if ((e->pos -= diff) < 0)
+ e->dir = DIR_FORWARD;
+ }
+ if (e->dir == DIR_FORWARD)
+ e->pos = BALIGN_CEIL((e->pos + diff) % (e->max + 1),
+ BLOCK_SIZE);
+ if (--e->dircnt < 0) {
+ e->dir = (e->dir == DIR_FORWARD ?
+ DIR_BACKWARDS : DIR_FORWARD);
+ e->dircnt = DIRECTION_MIN +
+ (random() % (DIRECTION_MAX - DIRECTION_MIN));
+ }
- /* Finally read block and clear buffer */
+ /* Seek and read block(s) */
+ if (lseek(e->fd, e->pos, SEEK_SET) != -1) {
+ if (read(e->fd, readbuf, blocks * BLOCK_SIZE) !=
+ blocks * BLOCK_SIZE)
+ (void) fprintf(stderr,
+ "read(%s, %llu, %u): %s\n",
+ e->name, e->pos, blocks * BLOCK_SIZE,
+ strerror(errno));
+ } else
+ (void) fprintf(stderr,
+ "lseek(%s, %llu): %s\n",
+ e->name, e->pos, strerror(errno));
/* Sleep for a slight random delay */
(void) usleep(random() % 1000);
"lseek(%s): %s\n", devname, strerror(errno));
goto err;
}
- e->lastpos = -1;
- e->lastdir = 0;
+ /*
+ * Substract so that any position is valid for reading up to
+ * BLOCK_SIZE * BLOCK_MULTIPLE bytes. We also ensure that size
+ * is always a multiple of BLOCK_SIZE.
+ */
+ e->max = BALIGN_CEIL(e->max - (BLOCK_SIZE * BLOCK_MULTIPLE),
+ BLOCK_SIZE);
+
+ /* Set a random but valid start position, BLOCK_SIZE aligned. */
+ e->pos = BALIGN_CEIL(((off_t)random() * (off_t)random()) %
+ (e->max + 1), BLOCK_SIZE);
+
+ /* And a random direction/count */
+ e->dir = random() % 2;
+ e->dircnt = DIRECTION_MIN +
+ (random() % (DIRECTION_MAX - DIRECTION_MIN));
SLIST_INSERT_HEAD(&disks_list, e, chain);
ndisks++;