From: Matthew Mondor Date: Wed, 9 Aug 2023 04:33:53 +0000 (+0000) Subject: util/hdnoidle.c: Cleanup; use BSD SLIST macros also in glibc. X-Git-Url: http://git.pulsar-zone.net/?a=commitdiff_plain;h=8707ab1996034d61696137489f99266079012c6d;p=mmondor.git util/hdnoidle.c: Cleanup; use BSD SLIST macros also in glibc. --- diff --git a/mmsoftware/util/hdnoidle.c b/mmsoftware/util/hdnoidle.c index 3fa7aa7..10c4172 100644 --- a/mmsoftware/util/hdnoidle.c +++ b/mmsoftware/util/hdnoidle.c @@ -63,8 +63,9 @@ */ -#define CONFIG "/usr/local/etc/hdnoidle.conf" -#define CONFIG_LZ 256 +#define CONFIG "/usr/local/etc/hdnoidle.conf" +#define CONFIG_LZ 256 +#define BLOCK_BUFSIZE 65536 /* Linux may use 32-bit off_t, other unix systems long use 64-bit. */ @@ -96,10 +97,12 @@ #if defined (__NetBSD__) || defined (__FreeBSD__) #include /* DIOCGMEDIASIZE, DIOCGSECTORSIZE */ #endif +#include /* BSD SLIST macros, also in glibc. */ /* Control structure for each disk */ typedef struct noidledisk { + SLIST_ENTRY(noidledisk) next; const char *dev; /* Device file */ int fd; /* Raw or unbuffered device file handle */ unsigned int delay, t; /* Delay in seconds between reads, current */ @@ -108,15 +111,18 @@ typedef struct noidledisk { uint8_t *sbuf; /* Buffer to use when reading a block */ } noidledisk_t; +SLIST_HEAD(noidledisk_list, noidledisk); + int main(void); -void conf_read(noidledisk_t **, int *); -void conf_setup(noidledisk_t *, int); +void conf_read(void); +void conf_setup(void); int disk_getsize(int, off_t *); ssize_t disk_getblocksize(int); uint8_t *membuf = NULL; +struct noidledisk_list disks; /* @@ -150,75 +156,70 @@ straspl(char **argv, char *str, int maxcols) } void -conf_read(noidledisk_t **disks, int *dn) +conf_read(void) { - noidledisk_t *dmem = NULL; FILE *fh; - int n = 0, i; + int n = 0, l = 0; char *cols[3] = { NULL, NULL, NULL }; char line[CONFIG_LZ + 1]; + SLIST_INIT(&disks); + + /* Read configuration file, populating list */ if ((fh = fopen(CONFIG, "r")) == NULL) err(EXIT_FAILURE, "fopen(%s)", CONFIG); - /* Count non-comment lines matching required number of columns */ while (fgets(line, CONFIG_LZ, fh) != NULL) { - line[CONFIG_LZ] = '\0'; - if (*line != '#') { - if (straspl(cols, line, 2) == 2) - n++; - } - } - (void)fclose(fh); + noidledisk_t *d = NULL, *d2; - /* Allocate structs */ - if ((dmem = malloc(sizeof(noidledisk_t) * n)) == NULL) - err(EXIT_FAILURE, "malloc()"); - - /* - * Reopen and fill structs. There's a possible race condition between - * the above and this, but we ensure not to configure more than . - * If there are more lines than expected, we ignore them. If there - * are less, we adjust . - */ - if ((fh = fopen(CONFIG, "r")) == NULL) - err(EXIT_FAILURE, "fopen(%s)", CONFIG); - for (i = 0; i < n && fgets(line, CONFIG_LZ, fh) != NULL; ) { + l++; line[CONFIG_LZ] = '\0'; 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++; + if (straspl(cols, line, 2) != 2) + err(EXIT_FAILURE, + "hdnoidle: Invalid configuration line #%d in %s", + l, CONFIG); + + /* Check if unique */ + SLIST_FOREACH(d2, &disks, next) { + if (strcmp(d2->dev, cols[0]) == 0) + err(EXIT_FAILURE, + "hdnoidle: Duplicate entry for %s at " + "line #%d in %s", d2->dev, l, CONFIG); } + + /* Allocate new entry and add to list */ + n++; + if ((d = malloc(sizeof(noidledisk_t))) == NULL) + err(EXIT_FAILURE, "malloc()"); + if ((d->dev = strdup(cols[0])) == NULL) + err(EXIT_FAILURE, "strdup()"); + if ((d->delay = atoi(cols[1])) < 1) + err(EXIT_FAILURE, + "hdnoidle: Invalid delay %d at line #%d in %s", + d->delay, l, CONFIG); + SLIST_INSERT_HEAD(&disks, d, next); } (void)fclose(fh); - if (i < 1) - err(EXIT_FAILURE, "hdnoidle: Quitting, no disk configured."); - *disks = dmem; - *dn = i; + if (n < 1) + err(EXIT_FAILURE, "hdnoidle: Quitting, no disk configured."); } void -conf_setup(noidledisk_t *disks, int nd) +conf_setup(void) { - int i; + noidledisk_t *d; /* * 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)"); + if ((membuf = malloc(BLOCK_BUFSIZE)) == NULL) + err(EXIT_FAILURE, "malloc()"); - for (i = 0; i < nd; i++) { + SLIST_FOREACH(d, &disks, next) { int pad; - noidledisk_t *d = &disks[i]; /* * O_DIRECT has no effect when already using a raw device but @@ -226,7 +227,8 @@ conf_setup(noidledisk_t *disks, int nd) * this to hopefully offer similar behavior. */ if ((d->fd = open(d->dev, O_RDONLY | O_DIRECT)) == -1) - err(EXIT_FAILURE, "open(%s)", d->dev); + err(EXIT_FAILURE, "hdnoidle: Cannot 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) @@ -244,7 +246,7 @@ conf_setup(noidledisk_t *disks, int nd) if ((pad = (uintptr_t)d->sbuf % d->bsize) > 0) pad = d->bsize - pad; d->sbuf += pad; - if (&d->sbuf[d->bsize] > &membuf[65535]) + if (&d->sbuf[d->bsize] > &membuf[BLOCK_BUFSIZE - 1]) err(EXIT_FAILURE, "Device block size for %s larger than expected!", d->dev); @@ -296,61 +298,57 @@ disk_getblocksize(int fd) int main(void) { - noidledisk_t *disks = NULL; - int nd = 0, i; + noidledisk_t *d; - conf_read(&disks, &nd); - conf_setup(disks, nd); + conf_read(); + conf_setup(); /* * Loop through configured disks, reading data and updating the offset * when their timer expires. */ for (;;) { + /* Every second */ (void)sleep(1); - for (i = 0; i < nd; i++) { - noidledisk_t *d = &disks[i]; - if (--d->t < 1) { - off_t pad; - ssize_t rz; + SLIST_FOREACH(d, &disks, next) { + off_t pad; + ssize_t rz; - /* Reset timer */ - d->t = d->delay; + if (--d->t > 0) + continue; - /* Seek to current offset */ - if (lseek(d->fd, d->offset, SEEK_SET) == -1) { - warn("seek(%s, %" PRIu64 ")", d->dev, - d->offset); - continue; - } - - /* 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, + /* Expired, 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); - else - (void)memset(d->sbuf, '\0', rz); - - /* - * Skip forward somewhat arbitrarily hoping to - * hit a non-cached block and to defeat - * readahead. - */ - d->offset += (d->bsize * 1000) + - (random() % (d->bsize * 100000)); - /* Align to block size */ - if ((pad = d->offset % d->bsize) > 0) - pad = d->bsize - pad; - d->offset += pad; - /* Wrap if overflow */ - if (d->offset + d->bsize >= d->size) - d->offset = 0; + continue; } + + /* 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); + else + (void)memset(d->sbuf, '\0', rz); + + /* + * Skip forward somewhat arbitrarily hoping to hit a + * non-cached block and to defeat readahead. + */ + d->offset += (d->bsize * 1000) + + (random() % (d->bsize * 100000)); + /* Align to block size */ + if ((pad = d->offset % d->bsize) > 0) + pad = d->bsize - pad; + d->offset += pad; + /* Wrap if overflow */ + if (d->offset + d->bsize >= d->size) + d->offset = 0; } }