-static int get_io_ticks(struct disk_util *du, struct disk_util_stat *dus)
-{
- unsigned in_flight;
- char line[256];
- FILE *f;
- char *p;
-
- f = fopen(du->path, "r");
- if (!f)
- return 1;
-
- p = fgets(line, sizeof(line), f);
- if (!p) {
- fclose(f);
- return 1;
- }
-
- if (sscanf(p, "%u %u %llu %u %u %u %llu %u %u %u %u\n", &dus->ios[0], &dus->merges[0], &dus->sectors[0], &dus->ticks[0], &dus->ios[1], &dus->merges[1], &dus->sectors[1], &dus->ticks[1], &in_flight, &dus->io_ticks, &dus->time_in_queue) != 11) {
- fclose(f);
- return 1;
- }
-
- fclose(f);
- return 0;
-}
-
-static void update_io_tick_disk(struct disk_util *du)
-{
- struct disk_util_stat __dus, *dus, *ldus;
- struct timeval t;
-
- if (get_io_ticks(du, &__dus))
- return;
-
- dus = &du->dus;
- ldus = &du->last_dus;
-
- dus->sectors[0] += (__dus.sectors[0] - ldus->sectors[0]);
- dus->sectors[1] += (__dus.sectors[1] - ldus->sectors[1]);
- dus->ios[0] += (__dus.ios[0] - ldus->ios[0]);
- dus->ios[1] += (__dus.ios[1] - ldus->ios[1]);
- dus->merges[0] += (__dus.merges[0] - ldus->merges[0]);
- dus->merges[1] += (__dus.merges[1] - ldus->merges[1]);
- dus->ticks[0] += (__dus.ticks[0] - ldus->ticks[0]);
- dus->ticks[1] += (__dus.ticks[1] - ldus->ticks[1]);
- dus->io_ticks += (__dus.io_ticks - ldus->io_ticks);
- dus->time_in_queue += (__dus.time_in_queue - ldus->time_in_queue);
-
- fio_gettime(&t, NULL);
- du->msec += mtime_since(&du->time, &t);
- memcpy(&du->time, &t, sizeof(t));
- memcpy(ldus, &__dus, sizeof(__dus));
-}
-
-void update_io_ticks(void)
-{
- struct list_head *entry;
- struct disk_util *du;
-
- list_for_each(entry, &disk_list) {
- du = list_entry(entry, struct disk_util, list);
- update_io_tick_disk(du);
- }
-}
-
-static int disk_util_exists(dev_t dev)
-{
- struct list_head *entry;
- struct disk_util *du;
-
- list_for_each(entry, &disk_list) {
- du = list_entry(entry, struct disk_util, list);
-
- if (du->dev == dev)
- return 1;
- }
-
- return 0;
-}
-
-static void disk_util_add(dev_t dev, char *path)
-{
- struct disk_util *du, *__du;
- struct list_head *entry;
-
- du = malloc(sizeof(*du));
- memset(du, 0, sizeof(*du));
- INIT_LIST_HEAD(&du->list);
- sprintf(du->path, "%s/stat", path);
- du->name = strdup(basename(path));
- du->dev = dev;
-
- list_for_each(entry, &disk_list) {
- __du = list_entry(entry, struct disk_util, list);
-
- if (!strcmp(du->name, __du->name)) {
- free(du->name);
- free(du);
- return;
- }
- }
-
- fio_gettime(&du->time, NULL);
- get_io_ticks(du, &du->last_dus);
-
- list_add_tail(&du->list, &disk_list);
-}
-
-static int check_dev_match(dev_t dev, char *path)
-{
- unsigned int major, minor;
- char line[256], *p;
- FILE *f;
-
- f = fopen(path, "r");
- if (!f) {
- perror("open path");
- return 1;
- }
-
- p = fgets(line, sizeof(line), f);
- if (!p) {
- fclose(f);
- return 1;
- }
-
- if (sscanf(p, "%u:%u", &major, &minor) != 2) {
- fclose(f);
- return 1;
- }
-
- if (((major << 8) | minor) == dev) {
- fclose(f);
- return 0;
- }
-
- fclose(f);
- return 1;
-}
-
-static int find_block_dir(dev_t dev, char *path)
-{
- struct dirent *dir;
- struct stat st;
- int found = 0;
- DIR *D;
-
- D = opendir(path);
- if (!D)
- return 0;
-
- while ((dir = readdir(D)) != NULL) {
- char full_path[256];
-
- if (!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, ".."))
- continue;
-
- sprintf(full_path, "%s/%s", path, dir->d_name);
-
- if (!strcmp(dir->d_name, "dev")) {
- if (!check_dev_match(dev, full_path)) {
- found = 1;
- break;
- }
- }
-
- if (lstat(full_path, &st) == -1) {
- perror("stat");
- break;
- }
-
- if (!S_ISDIR(st.st_mode) || S_ISLNK(st.st_mode))
- continue;
-
- found = find_block_dir(dev, full_path);
- if (found) {
- strcpy(path, full_path);
- break;
- }
- }
-
- closedir(D);
- return found;
-}
-
-void init_disk_util(struct thread_data *td)
-{
- struct fio_file *f;
- struct stat st;
- char foo[PATH_MAX], tmp[PATH_MAX];
- dev_t dev;
- char *p;
-
- if (!td->do_disk_util || (td->io_ops->flags & FIO_DISKLESSIO))
- return;
-
- /*
- * Just use the same file, they are on the same device.
- */
- f = &td->files[0];
- if (!stat(f->file_name, &st)) {
- if (S_ISBLK(st.st_mode))
- dev = st.st_rdev;
- else
- dev = st.st_dev;
- } else {
- /*
- * must be a file, open "." in that path
- */
- strncpy(foo, f->file_name, PATH_MAX - 1);
- p = dirname(foo);
- if (stat(p, &st)) {
- perror("disk util stat");
- return;
- }
-
- dev = st.st_dev;
- }
-
- if (disk_util_exists(dev))
- return;
-
- /*
- * for an fs without a device, we will repeatedly stat through
- * sysfs which can take oodles of time for thousands of files. so
- * cache the last lookup and compare with that before going through
- * everything again.
- */
- if (dev == last_dev)
- return;
-
- last_dev = dev;
-
- sprintf(foo, "/sys/block");
- if (!find_block_dir(dev, foo))
- return;
-
- /*
- * If there's a ../queue/ directory there, we are inside a partition.
- * Check if that is the case and jump back. For loop/md/dm etc we
- * are already in the right spot.
- */
- sprintf(tmp, "%s/../queue", foo);
- if (!stat(tmp, &st)) {
- p = dirname(foo);
- sprintf(tmp, "%s/queue", p);
- if (stat(tmp, &st)) {
- log_err("unknown sysfs layout\n");
- return;
- }
- strncpy(tmp, p, PATH_MAX - 1);
- sprintf(foo, "%s", tmp);
- }
-
- if (td->ioscheduler)
- td->sysfs_root = strdup(foo);
-
- disk_util_add(dev, foo);
-}
-
-void disk_util_timer_arm(void)
-{
- itimer.it_value.tv_sec = 0;
- itimer.it_value.tv_usec = DISK_UTIL_MSEC * 1000;
- setitimer(ITIMER_REAL, &itimer, NULL);
-}
-