Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf hwmon_pmu: Hold path rather than fd

Hold the path to the hwmon_pmu rather than the file descriptor. The
file descriptor is somewhat problematic in that it reflects the
directory state when opened, something that may vary in testing. Using
a path simplifies testing and to some extent cleanup as the hwmon_pmu
is owned by the pmus list and intentionally global and leaked when
perf terminates, the file descriptor being left open looks like a
leak.

Signed-off-by: Ian Rogers <irogers@google.com>
Link: https://lore.kernel.org/r/20250624190326.2038704-4-irogers@google.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>

authored by

Ian Rogers and committed by
Namhyung Kim
d1f18106 7a8557fc

+38 -19
+6 -5
tools/perf/tests/hwmon_pmu.c
··· 93 93 pr_err("Failed to mkdir hwmon directory\n"); 94 94 goto err_out; 95 95 } 96 - hwmon_dirfd = openat(test_dirfd, "hwmon1234", O_DIRECTORY); 96 + strncat(dir, "/hwmon1234", sz - strlen(dir)); 97 + hwmon_dirfd = open(dir, O_PATH|O_DIRECTORY); 97 98 if (hwmon_dirfd < 0) { 98 - pr_err("Failed to open test hwmon directory \"%s/hwmon1234\"\n", dir); 99 + pr_err("Failed to open test hwmon directory \"%s\"\n", dir); 99 100 goto err_out; 100 101 } 101 102 file = openat(hwmon_dirfd, "name", O_WRONLY | O_CREAT, 0600); ··· 131 130 } 132 131 133 132 /* Make the PMU reading the files created above. */ 134 - hwm = perf_pmus__add_test_hwmon_pmu(hwmon_dirfd, "hwmon1234", test_hwmon_name); 133 + hwm = perf_pmus__add_test_hwmon_pmu(dir, "hwmon1234", test_hwmon_name); 135 134 if (!hwm) 136 135 pr_err("Test hwmon creation failed\n"); 137 136 138 137 err_out: 139 138 if (!hwm) { 140 139 test_pmu_put(dir, hwm); 141 - if (hwmon_dirfd >= 0) 142 - close(hwmon_dirfd); 143 140 } 144 141 if (test_dirfd >= 0) 145 142 close(test_dirfd); 143 + if (hwmon_dirfd >= 0) 144 + close(hwmon_dirfd); 146 145 return hwm; 147 146 } 148 147
+28 -10
tools/perf/util/hwmon_pmu.c
··· 104 104 struct hwmon_pmu { 105 105 struct perf_pmu pmu; 106 106 struct hashmap events; 107 - int hwmon_dir_fd; 107 + char *hwmon_dir; 108 108 }; 109 109 110 110 /** ··· 245 245 return 0; 246 246 247 247 /* Use openat so that the directory contents are refreshed. */ 248 - io_dir__init(&dir, openat(pmu->hwmon_dir_fd, ".", O_CLOEXEC | O_DIRECTORY | O_RDONLY)); 248 + io_dir__init(&dir, open(pmu->hwmon_dir, O_CLOEXEC | O_DIRECTORY | O_RDONLY)); 249 249 250 250 if (dir.dirfd < 0) 251 251 return -ENOENT; ··· 283 283 __set_bit(item, alarm ? value->alarm_items : value->items); 284 284 if (item == HWMON_ITEM_LABEL) { 285 285 char buf[128]; 286 - int fd = openat(pmu->hwmon_dir_fd, ent->d_name, O_RDONLY); 286 + int fd = openat(dir.dirfd, ent->d_name, O_RDONLY); 287 287 ssize_t read_len; 288 288 289 289 if (fd < 0) ··· 342 342 return err; 343 343 } 344 344 345 - struct perf_pmu *hwmon_pmu__new(struct list_head *pmus, int hwmon_dir, const char *sysfs_name, const char *name) 345 + struct perf_pmu *hwmon_pmu__new(struct list_head *pmus, const char *hwmon_dir, 346 + const char *sysfs_name, const char *name) 346 347 { 347 348 char buf[32]; 348 349 struct hwmon_pmu *hwm; ··· 366 365 return NULL; 367 366 } 368 367 369 - hwm->hwmon_dir_fd = hwmon_dir; 368 + hwm->hwmon_dir = strdup(hwmon_dir); 369 + if (!hwm->hwmon_dir) { 370 + perf_pmu__delete(&hwm->pmu); 371 + return NULL; 372 + } 370 373 hwm->pmu.alias_name = strdup(sysfs_name); 371 374 if (!hwm->pmu.alias_name) { 372 375 perf_pmu__delete(&hwm->pmu); ··· 404 399 free(value); 405 400 } 406 401 hashmap__clear(&hwm->events); 407 - close(hwm->hwmon_dir_fd); 402 + zfree(&hwm->hwmon_dir); 408 403 } 409 404 410 405 static size_t hwmon_pmu__describe_items(struct hwmon_pmu *hwm, char *out_buf, size_t out_buf_len, ··· 414 409 size_t bit; 415 410 char buf[64]; 416 411 size_t len = 0; 412 + int dir = open(hwm->hwmon_dir, O_CLOEXEC | O_DIRECTORY | O_RDONLY); 413 + 414 + if (dir < 0) 415 + return 0; 417 416 418 417 for_each_set_bit(bit, items, HWMON_ITEM__MAX) { 419 418 int fd; ··· 430 421 key.num, 431 422 hwmon_item_strs[bit], 432 423 is_alarm ? "_alarm" : ""); 433 - fd = openat(hwm->hwmon_dir_fd, buf, O_RDONLY); 424 + fd = openat(dir, buf, O_RDONLY); 434 425 if (fd > 0) { 435 426 ssize_t read_len = read(fd, buf, sizeof(buf)); 436 427 ··· 452 443 close(fd); 453 444 } 454 445 } 446 + close(dir); 455 447 return len; 456 448 } 457 449 ··· 722 712 size_t line_len; 723 713 int hwmon_dir, name_fd; 724 714 struct io io; 715 + char buf2[128]; 725 716 726 717 if (class_hwmon_ent->d_type != DT_LNK) 727 718 continue; ··· 741 730 close(hwmon_dir); 742 731 continue; 743 732 } 744 - io__init(&io, name_fd, buf, sizeof(buf)); 733 + io__init(&io, name_fd, buf2, sizeof(buf2)); 745 734 io__getline(&io, &line, &line_len); 746 735 if (line_len > 0 && line[line_len - 1] == '\n') 747 736 line[line_len - 1] = '\0'; 748 - hwmon_pmu__new(pmus, hwmon_dir, class_hwmon_ent->d_name, line); 737 + hwmon_pmu__new(pmus, buf, class_hwmon_ent->d_name, line); 749 738 close(name_fd); 739 + close(hwmon_dir); 750 740 } 751 741 free(line); 752 742 close(class_hwmon_dir.dirfd); ··· 765 753 .type_and_num = evsel->core.attr.config, 766 754 }; 767 755 int idx = 0, thread = 0, nthreads, err = 0; 756 + int dir = open(hwm->hwmon_dir, O_CLOEXEC | O_DIRECTORY | O_RDONLY); 757 + 758 + if (dir < 0) 759 + return -errno; 768 760 769 761 nthreads = perf_thread_map__nr(threads); 770 762 for (idx = start_cpu_map_idx; idx < end_cpu_map_idx; idx++) { ··· 779 763 snprintf(buf, sizeof(buf), "%s%d_input", 780 764 hwmon_type_strs[key.type], key.num); 781 765 782 - fd = openat(hwm->hwmon_dir_fd, buf, O_RDONLY); 766 + fd = openat(dir, buf, O_RDONLY); 783 767 FD(evsel, idx, thread) = fd; 784 768 if (fd < 0) { 785 769 err = -errno; ··· 787 771 } 788 772 } 789 773 } 774 + close(dir); 790 775 return 0; 791 776 out_close: 792 777 if (err) ··· 801 784 } 802 785 thread = nthreads; 803 786 } while (--idx >= 0); 787 + close(dir); 804 788 return err; 805 789 } 806 790
+2 -2
tools/perf/util/hwmon_pmu.h
··· 135 135 * hwmon_pmu__new() - Allocate and construct a hwmon PMU. 136 136 * 137 137 * @pmus: The list of PMUs to be added to. 138 - * @hwmon_dir: An O_DIRECTORY file descriptor for a hwmon directory. 138 + * @hwmon_dir: The path to a hwmon directory. 139 139 * @sysfs_name: Name of the hwmon sysfs directory like hwmon0. 140 140 * @name: The contents of the "name" file in the hwmon directory. 141 141 * 142 142 * Exposed for testing. Regular construction should happen via 143 143 * perf_pmus__read_hwmon_pmus. 144 144 */ 145 - struct perf_pmu *hwmon_pmu__new(struct list_head *pmus, int hwmon_dir, 145 + struct perf_pmu *hwmon_pmu__new(struct list_head *pmus, const char *hwmon_dir, 146 146 const char *sysfs_name, const char *name); 147 147 void hwmon_pmu__exit(struct perf_pmu *pmu); 148 148
+1 -1
tools/perf/util/pmus.c
··· 861 861 return perf_pmu__lookup(&other_pmus, test_sysfs_dirfd, name, /*eager_load=*/true); 862 862 } 863 863 864 - struct perf_pmu *perf_pmus__add_test_hwmon_pmu(int hwmon_dir, 864 + struct perf_pmu *perf_pmus__add_test_hwmon_pmu(const char *hwmon_dir, 865 865 const char *sysfs_name, 866 866 const char *name) 867 867 {
+1 -1
tools/perf/util/pmus.h
··· 31 31 bool perf_pmus__supports_extended_type(void); 32 32 33 33 struct perf_pmu *perf_pmus__add_test_pmu(int test_sysfs_dirfd, const char *name); 34 - struct perf_pmu *perf_pmus__add_test_hwmon_pmu(int hwmon_dir, 34 + struct perf_pmu *perf_pmus__add_test_hwmon_pmu(const char *hwmon_dir, 35 35 const char *sysfs_name, 36 36 const char *name); 37 37 struct perf_pmu *perf_pmus__fake_pmu(void);