From: Cyril Hrubis <chrubis@suse.cz>
To: Praveen K Pandey <praveen@linux.ibm.com>
Cc: ltp@lists.linux.it
Subject: Re: [LTP] [PATCH v6 1/5] ftrace: Add common library for C implementation
Date: Wed, 10 Jun 2026 11:31:09 +0200 [thread overview]
Message-ID: <aiku3VRfJZS4dsxY@yuki.lan> (raw)
In-Reply-To: <20260609041632.74427-2-praveen@linux.ibm.com>
Hi!
> +char *ftrace_get_path(const char *filename)
> +{
> + char *path;
> +
> + SAFE_ASPRINTF(&path, "%s/%s", tracing_path, filename);
> + return path;
> +}
> +
> +char *ftrace_read_file(const char *filename)
> +{
> + char *path;
> + FILE *fp;
> + char *content = NULL;
> + size_t len = 0;
> + ssize_t read;
> + char *line = NULL;
> + size_t total_size = 0;
> +
> + path = ftrace_get_path(filename);
> + if (!path)
> + return NULL;
> +
> + fp = fopen(path, "r");
> + free(path);
> +
> + if (!fp)
> + return NULL;
> +
> + while ((read = getline(&line, &len, fp)) != -1) {
> + char *new_content = realloc(content, total_size + read + 1);
> +
> + if (!new_content) {
> + free(content);
> + free(line);
> + fclose(fp);
> + return NULL;
> + }
> + content = new_content;
> + memcpy(content + total_size, line, read);
> + total_size += read;
> + }
> +
> + if (content)
> + content[total_size] = '\0';
> +
> + free(line);
> + fclose(fp);
> +
> + return content;
> +}
> +
> +int ftrace_write_file(const char *filename, const char *content)
> +{
> + char *path;
> + FILE *fp;
> + int ret;
> +
> + path = ftrace_get_path(filename);
> + if (!path)
> + return -1;
> +
> + fp = fopen(path, "w");
> + free(path);
> +
> + if (!fp)
> + return -1;
> +
> + ret = fprintf(fp, "%s", content);
> + fclose(fp);
> +
> + return (ret > 0) ? 0 : -1;
> +}
> +
> +int ftrace_file_exists(const char *filename)
> +{
> + char *path;
> + int ret;
> +
> + path = ftrace_get_path(filename);
> + if (!path)
> + return 0;
> +
> + ret = (access(path, F_OK) == 0);
> + free(path);
> +
> + return ret;
> +}
> +
> +void ftrace_save_settings(void)
> +{
> + if (saved_state.saved)
> + return;
> +
> + saved_state.trace_options = ftrace_read_file("trace_options");
> + saved_state.tracing_on = ftrace_read_file("tracing_on");
> + saved_state.buffer_size = ftrace_read_file("buffer_size_kb");
> +
> + if (ftrace_file_exists("tracing_cpumask"))
> + saved_state.tracing_cpumask = ftrace_read_file("tracing_cpumask");
> +
> + if (ftrace_file_exists("tracing_enabled"))
> + saved_state.tracing_enabled = ftrace_read_file("tracing_enabled");
> +
> + if (ftrace_file_exists("stack_max_size")) {
> + FILE *fp = fopen("/proc/sys/kernel/stack_tracer_enabled", "r");
> +
> + if (fp) {
> + saved_state.stack_tracer_enabled = malloc(32);
> + if (saved_state.stack_tracer_enabled)
> + fgets(saved_state.stack_tracer_enabled, 32, fp);
> + fclose(fp);
> + }
> + }
> +
> + if (access("/proc/sys/kernel/ftrace_enabled", F_OK) == 0) {
> + FILE *fp = fopen("/proc/sys/kernel/ftrace_enabled", "r");
> +
> + if (fp) {
> + saved_state.ftrace_enabled = malloc(32);
> + if (saved_state.ftrace_enabled)
> + fgets(saved_state.ftrace_enabled, 32, fp);
> + fclose(fp);
> + }
> + }
> +
> + if (ftrace_file_exists("function_profile_enabled"))
> + saved_state.function_profile_enabled = ftrace_read_file("function_profile_enabled");
> +
> + saved_state.saved = 1;
> +}
> +
> +void ftrace_restore_settings(void)
> +{
> + if (!saved_state.saved)
> + return;
> +
> + ftrace_write_file("current_tracer", "nop\n");
> + ftrace_write_file("events/enable", "0\n");
> +
> + if (ftrace_file_exists("tracing_max_latency"))
> + ftrace_write_file("tracing_max_latency", "0\n");
> +
> + if (saved_state.tracing_cpumask)
> + ftrace_write_file("tracing_cpumask", saved_state.tracing_cpumask);
> +
> + if (ftrace_file_exists("trace_clock"))
> + ftrace_write_file("trace_clock", "local\n");
> +
> + if (saved_state.function_profile_enabled)
> + ftrace_write_file("function_profile_enabled", saved_state.function_profile_enabled);
> +
> + if (saved_state.ftrace_enabled) {
> + FILE *fp = fopen("/proc/sys/kernel/ftrace_enabled", "w");
> +
> + if (fp) {
> + fprintf(fp, "%s", saved_state.ftrace_enabled);
> + fclose(fp);
> + }
> + }
> +
> + if (saved_state.stack_tracer_enabled && ftrace_file_exists("stack_max_size")) {
> + FILE *fp = fopen("/proc/sys/kernel/stack_tracer_enabled", "w");
> +
> + if (fp) {
> + fprintf(fp, "%s", saved_state.stack_tracer_enabled);
> + fclose(fp);
> + }
> + ftrace_write_file("stack_max_size", "0\n");
> + }
> +
> + if (saved_state.buffer_size)
> + ftrace_write_file("buffer_size_kb", saved_state.buffer_size);
> +
> + if (saved_state.tracing_on)
> + ftrace_write_file("tracing_on", saved_state.tracing_on);
> +
> + if (saved_state.tracing_enabled)
> + ftrace_write_file("tracing_enabled", saved_state.tracing_enabled);
> +
> + if (saved_state.trace_options) {
> + char *options = strdup(saved_state.trace_options);
> +
> + if (options) {
> + char *token = strtok(options, "\n");
> +
> + while (token) {
> + ftrace_write_file("trace_options", token);
> + token = strtok(NULL, "\n");
> + }
> + free(options);
> + }
> + }
> +
> + ftrace_clear_trace();
> +
> + if (ftrace_file_exists("set_ftrace_filter"))
> + ftrace_write_file("set_ftrace_filter", "\n");
> +}
> +
> +char **ftrace_get_available_tracers(int *count)
> +{
> + char *path;
> + FILE *fp;
> + char **tracers = NULL;
> + char *line = NULL;
> + size_t len = 0;
> + int n = 0;
> + int capacity = 16;
> +
> + path = ftrace_get_path("available_tracers");
> + if (!path) {
> + *count = 0;
> + return NULL;
> + }
> +
> + fp = fopen(path, "r");
> + free(path);
> +
> + if (!fp) {
> + *count = 0;
> + return NULL;
> + }
> +
> + tracers = malloc(sizeof(char *) * capacity);
> + if (!tracers) {
> + fclose(fp);
> + *count = 0;
> + return NULL;
> + }
> +
> + if (getline(&line, &len, fp) != -1) {
> + char *token;
> + char *saveptr;
> +
> + token = strtok_r(line, " \n", &saveptr);
> + while (token) {
> + if (n >= capacity) {
> + capacity *= 2;
> + char **new_tracers = realloc(tracers, sizeof(char *) * capacity);
> +
> + if (!new_tracers) {
> + while (n > 0)
> + free(tracers[--n]);
> + free(tracers);
> + free(line);
> + fclose(fp);
> + *count = 0;
> + return NULL;
> + }
> + tracers = new_tracers;
> + }
> +
> + tracers[n] = strdup(token);
> + if (!tracers[n]) {
> + while (n > 0)
> + free(tracers[--n]);
> + free(tracers);
> + free(line);
> + fclose(fp);
> + *count = 0;
> + return NULL;
> + }
> + n++;
> + token = strtok_r(NULL, " \n", &saveptr);
> + }
The loop here does not make any sense, we are reading the file line by
line now, the strtok_r() will not split the line into tokens, there is
going to be only a single line in the buffer.
> + }
> +
> + free(line);
> + fclose(fp);
> +
> + *count = n;
> + return tracers;
> +}
> +
> +int ftrace_set_tracer(const char *tracer)
> +{
> + char *path;
> +
> + path = ftrace_get_path("current_tracer");
> + if (!path)
> + return -1;
> +
> + SAFE_FILE_PRINTF(path, "%s", tracer);
> + free(path);
> +
> + return 0;
It's way too ugly to construct the path each time we need to write to
the tracing file.
I guess that the ideal solution is to use the SAFE_FILE_PRINTFAT() that
way we will only need to open the tracing directory with O_DIRECTORY in
the ftrace_initialize() and then we can print to all these files
relative to the dirfd without construction any paths, which can replace
all the ftrace_write_file() with SAFE_FILE_PRINTFAT().
For reading small files we can use SAFE_FILE_READAT().
> diff --git a/testcases/kernel/tracing/ftrace_test/ftrace_lib.h b/testcases/kernel/tracing/ftrace_test/ftrace_lib.h
> new file mode 100644
> index 000000000..79fdfee28
> --- /dev/null
> +++ b/testcases/kernel/tracing/ftrace_test/ftrace_lib.h
> @@ -0,0 +1,136 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Copyright (c) 2010 FUJITSU LIMITED
> + * Copyright (c) 2024 Linux Test Project
> + * Copyright (c) IBM, 2026
> + *
> + * Author: Li Zefan <lizf@cn.fujitsu.com>
> + * Converted to C by: Praveen K Pandey <praveen@linux.ibm.com>
> + */
> +
> +#ifndef FTRACE_LIB_H
> +#define FTRACE_LIB_H
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <fcntl.h>
> +#include <sys/mount.h>
> +#include <sys/stat.h>
> +#include <sys/types.h>
> +#include <errno.h>
> +#include <limits.h>
> +
> +extern char *tracing_path;
> +extern char *debugfs_path;
> +
> +struct ftrace_saved_state {
> + char *trace_options;
> + char *tracing_on;
> + char *buffer_size;
> + char *tracing_cpumask;
> + char *tracing_enabled;
> + char *stack_tracer_enabled;
> + char *ftrace_enabled;
> + char *function_profile_enabled;
> + int saved;
> +};
> +
> +extern struct ftrace_saved_state saved_state;
> +
> +/**
> + * ftrace_initialize - Initialize ftrace test environment
> + *
> + * Checks if debugfs is mounted, mounts it if needed, verifies tracing
> + * support, and saves current ftrace settings.
> + */
> +void ftrace_initialize(void);
> +
> +/**
> + * ftrace_cleanup - Cleanup and restore ftrace settings
> + *
> + * Restores all saved ftrace settings and unmounts debugfs if needed.
> + */
> +void ftrace_cleanup(void);
> +
> +/**
> + * ftrace_save_settings - Save current ftrace settings
> + *
> + * Saves all ftrace configuration to restore later.
> + */
> +void ftrace_save_settings(void);
> +
> +/**
> + * ftrace_restore_settings - Restore saved ftrace settings
> + *
> + * Restores ftrace configuration saved by ftrace_save_settings().
> + */
> +void ftrace_restore_settings(void);
> +
> +/**
> + * ftrace_get_path - Get full path to a tracing file
> + * @filename: Name of the file in tracing directory
> + *
> + * Return: Allocated string with full path (caller must free)
> + */
> +char *ftrace_get_path(const char *filename);
> +
> +/**
> + * ftrace_read_file - Read content from a tracing file
> + * @filename: Name of the file in tracing directory
> + *
> + * Return: Allocated string with file content (caller must free)
> + */
> +char *ftrace_read_file(const char *filename);
> +
> +/**
> + * ftrace_write_file - Write content to a tracing file
> + * @filename: Name of the file in tracing directory
> + * @content: Content to write
> + *
> + * Return: 0 on success, -1 on failure
> + */
> +int ftrace_write_file(const char *filename, const char *content);
> +
> +/**
> + * ftrace_file_exists - Check if a tracing file exists
> + * @filename: Name of the file in tracing directory
> + *
> + * Return: 1 if exists, 0 otherwise
> + */
> +int ftrace_file_exists(const char *filename);
> +
> +/**
> + * ftrace_get_available_tracers - Get list of available tracers
> + * @count: Pointer to store number of tracers
> + *
> + * Return: Array of tracer names (caller must free)
> + */
> +char **ftrace_get_available_tracers(int *count);
> +
> +/**
> + * ftrace_set_tracer - Set current tracer
> + * @tracer: Name of the tracer to set
> + *
> + * Return: 0 on success, -1 on failure
> + */
> +int ftrace_set_tracer(const char *tracer);
> +
> +/**
> + * ftrace_clear_trace - Clear the trace buffer
> + */
> +void ftrace_clear_trace(void);
> +
> +/**
> + * ftrace_enable_tracing - Enable tracing
> + */
> +void ftrace_enable_tracing(void);
> +
> +/**
> + * ftrace_disable_tracing - Disable tracing
> + */
> +void ftrace_disable_tracing(void);
> +
> +#endif /* FTRACE_LIB_H */
> +
> --
> 2.50.1
--
Cyril Hrubis
chrubis@suse.cz
--
Mailing list info: https://lists.linux.it/listinfo/ltp
next prev parent reply other threads:[~2026-06-10 9:31 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-09 4:16 [LTP] [PATCH v6 0/5] ftrace: Convert shell tests to C Praveen K Pandey
2026-06-09 4:16 ` [LTP] [PATCH v6 1/5] ftrace: Add common library for C implementation Praveen K Pandey
2026-06-09 5:14 ` [LTP] " linuxtestproject.agent
2026-06-10 9:31 ` Cyril Hrubis [this message]
2026-06-09 4:16 ` [LTP] [PATCH v6 2/5] ftrace: Convert ftrace_regression01.sh to C Praveen K Pandey
2026-06-09 4:16 ` [LTP] [PATCH v6 3/5] ftrace: Convert ftrace_regression02.sh " Praveen K Pandey
2026-06-09 4:16 ` [LTP] [PATCH v6 4/5] ftrace: Convert ftrace_stress_test.sh " Praveen K Pandey
2026-06-09 4:16 ` [LTP] [PATCH v6 5/5] ftrace: Remove obsolete shell test files Praveen K Pandey
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=aiku3VRfJZS4dsxY@yuki.lan \
--to=chrubis@suse.cz \
--cc=ltp@lists.linux.it \
--cc=praveen@linux.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.