ssize_t disk_getblocksize(int);
+uint8_t *membuf = NULL;
+
+
/*
* Splits columns of a string delimited by spaces and/or tabs, and fills
* char **argv with pointers to each column. Returns the number of columns
void
conf_read(noidledisk_t **disks, int *dn)
{
+ noidledisk_t *dmem = NULL;
FILE *fh;
- noidledisk_t *d = NULL;
int n = 0, i;
char *cols[3] = { NULL, NULL, NULL };
char line[CONFIG_LZ + 1];
(void)fclose(fh);
/* Allocate structs */
- if ((d = malloc(sizeof(noidledisk_t) * n)) == NULL)
+ if ((dmem = malloc(sizeof(noidledisk_t) * n)) == NULL)
err(EXIT_FAILURE, "malloc()");
- /* Reopen and fill structs */
+ /*
+ * Reopen and fill structs. There's a possible race condition between
+ * the above and this, but we ensure not to configure more than <n>.
+ * If there are more lines than expected, we ignore them. If there
+ * are less, we adjust <n>.
+ */
if ((fh = fopen(CONFIG, "r")) == NULL)
err(EXIT_FAILURE, "fopen(%s)", CONFIG);
- i = 0;
- while (fgets(line, CONFIG_LZ, fh) != NULL) {
+ for (i = 0; i < n && fgets(line, CONFIG_LZ, fh) != NULL; ) {
line[CONFIG_LZ] = '\0';
- if (*line != '#') {
- if (straspl(cols, line, 2) == 2) {
- if ((d[i].dev = strdup(cols[0])) == NULL)
- err(EXIT_FAILURE, "strdup()");
- if ((d[i].delay = atoi(cols[1])) < 1)
- err(EXIT_FAILURE, "atoi(delay) < 1");
- i++;
- }
+ if (*line == '#')
+ continue;
+ if (straspl(cols, line, 2) == 2) {
+ noidledisk_t *d = &dmem[i];
+
+ if ((d->dev = strdup(cols[0])) == NULL)
+ err(EXIT_FAILURE, "strdup()");
+ if ((d->delay = atoi(cols[1])) < 1)
+ err(EXIT_FAILURE, "atoi(delay) < 1");
+ i++;
}
}
(void)fclose(fh);
+ if (i < 1)
+ err(EXIT_FAILURE, "hdnoidle: Quitting, no disk configured.");
- if (i != n)
- err(EXIT_FAILURE, "conf_read() - i != n");
-
- *disks = d;
- *dn = n;
+ *disks = dmem;
+ *dn = i;
}
void
-conf_setup(noidledisk_t *d, int nd)
+conf_setup(noidledisk_t *disks, int nd)
{
int i;
+ /*
+ * Large buffer in which we'll custom-align smaller regions that can
+ * overlap and will only be used one at a time then discarded.
+ */
+ if ((membuf = malloc(65536)) == NULL)
+ err(EXIT_FAILURE, "malloc(65536)");
+
for (i = 0; i < nd; i++) {
- uint8_t *membuf;
int pad;
+ noidledisk_t *d = &disks[i];
/*
* O_DIRECT has no effect when already using a raw device but
* Linux now lacks real raw devices and apparently relies on
* this to hopefully offer similar behavior.
*/
- if ((d[i].fd = open(d[i].dev, O_RDONLY | O_DIRECT)) == -1)
- err(EXIT_FAILURE, "open(%s)", d[i].dev);
- if (disk_getsize(d[i].fd, &(d[i].size)) == -1)
- err(EXIT_FAILURE, "disk_getsize(%s)", d[i].dev);
- if ((d[i].bsize = disk_getblocksize(d[i].fd)) == -1)
- err(EXIT_FAILURE, "disk_getblocksize(%s)", d[i].dev);
+ if ((d->fd = open(d->dev, O_RDONLY | O_DIRECT)) == -1)
+ err(EXIT_FAILURE, "open(%s)", d->dev);
+ if (disk_getsize(d->fd, &(d->size)) == -1)
+ err(EXIT_FAILURE, "disk_getsize(%s)", d->dev);
+ if ((d->bsize = disk_getblocksize(d->fd)) == -1)
+ err(EXIT_FAILURE, "disk_getblocksize(%s)", d->dev);
- d[i].t = d[i].delay;
- d[i].offset = 0;
+ d->t = d->delay;
+ d->offset = 0;
/*
* We need memory to also be block-aligned. Since malloc(3)
* will only guarantee 32-bit or 64-bit aligned memory, let's
- * allocate a larger buffer and use an aligned sub-buffer.
+ * assign them an aligned sub-buffer in membuf.
*/
- if ((membuf = malloc(65536)) == NULL)
- err(EXIT_FAILURE, "malloc(65536)");
- d[i].sbuf = membuf;
-
- if ((d[i].sbuf = malloc(d[i].bsize)) == NULL)
- err(EXIT_FAILURE, "malloc(%lu)",
- (unsigned long)d[i].bsize);
- if ((pad = (uintptr_t)d[i].sbuf % d->bsize) > 0)
+ d->sbuf = membuf;
+ if ((pad = (uintptr_t)d->sbuf % d->bsize) > 0)
pad = d->bsize - pad;
- d[i].sbuf += pad;
- if (d[i].sbuf + d->bsize > &membuf[65536])
+ d->sbuf += pad;
+ if (&d->sbuf[d->bsize] > &membuf[65535])
err(EXIT_FAILURE,
"Device block size for %s larger than expected!",
- d[i].dev);
+ d->dev);
(void)printf("hdnoidle: device=%s, size=%" PRIu64 ", "
"blocksize=%lu, delay=%u\n",
- d[i].dev, d[i].size, (unsigned long)d[i].bsize,
- d[i].delay);
+ d->dev, d->size, (unsigned long)d->bsize, d->delay);
}
}
if (--d->t < 1) {
off_t pad;
+ ssize_t rz;
+ /* Reset timer */
d->t = d->delay;
+
+ /* Seek to current offset */
if (lseek(d->fd, d->offset, SEEK_SET) == -1) {
warn("seek(%s, %" PRIu64 ")", d->dev,
d->offset);
continue;
}
- if (read(d->fd, d->sbuf, d->bsize) == -1)
+
+ /* Read and discard by zeroing. */
+ if ((rz = read(d->fd, d->sbuf, d->bsize))
+ == -1)
warn("read(dev=%s (fd=%d), buf=%p, "
"sz=%lu) off=%" PRIu64,
d->dev, d->fd, d->sbuf,
(unsigned long)d->bsize,
d->offset);
+ (void)memset(d->sbuf, '\0', rz);
+
/*
* Skip forward somewhat arbitrarily hoping to
* hit a non-cached block and to defeat