All of lore.kernel.org
 help / color / mirror / Atom feed
From: Cyril Hrubis <chrubis@suse.cz>
To: Praveen K Pandey <praveen@linux.ibm.com>
Cc: ltp@lists.linux.it
Subject: Re: [LTP] [LTP PATCH v4 1/5] ftrace: Add common library for C implementation
Date: Mon, 8 Jun 2026 11:41:29 +0200	[thread overview]
Message-ID: <aiaOSb3OCJRd1Qry@yuki.lan> (raw)
In-Reply-To: <20260608055000.97154-2-praveen@linux.ibm.com>

Hi!
> diff --git a/testcases/kernel/tracing/ftrace_test/ftrace_lib.c b/testcases/kernel/tracing/ftrace_test/ftrace_lib.c
> new file mode 100644
> index 000000000..8b93b9849
> --- /dev/null
> +++ b/testcases/kernel/tracing/ftrace_test/ftrace_lib.c
> @@ -0,0 +1,358 @@
> +// 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>
> + */
> +
> +#define TST_NO_DEFAULT_MAIN
> +#include "ftrace_lib.h"
> +#include "tst_test.h"
> +#include "tst_safe_macros.h"
> +#include "tst_safe_stdio.h"
> +
> +char *tracing_path = NULL;
> +char *debugfs_path = NULL;
> +static int debugfs_mounted_by_us = 0;
> +struct ftrace_saved_state saved_state = {0};

Static variables are initialized to zero by compiler automatically, no
need to do it here.

> +void ftrace_initialize(void)
> +{
> +	FILE *fp;
> +	char line[PATH_MAX];
> +	int found = 0;
> +
> +	/* Check if debugfs is already mounted */

Please avoid comment that state the obvious, e.g. say in english exactly
what the code does.

> +	fp = SAFE_FOPEN("/proc/mounts", "r");
> +	while (fgets(line, sizeof(line), fp)) {
> +		if (strstr(line, "debugfs")) {
> +			debugfs_path = strdup("/sys/kernel/debug");
> +			found = 1;
> +			break;
> +		}
> +	}
> +	SAFE_FCLOSE(fp);

This whole thing could be just:

	if (tst_fs_is_mounted("/sys/kernel/debug")) {
		debugfs_path = strdup("/sys/kernel/debug");
		if (!debugfs_path)
			tst_brk(TBROK, ...);
	}

Ideally SAFE_STRDUP() should be added to the test library (in a separate
patch) so that we can simplify this even further to:

	if (tst_fs_is_mounted("/sys/kernel/debug"))
		debugfs_path = SAFE_STRDUP("/sys/kernel/debug");

> +	/* Mount debugfs if not already mounted */
> +	if (!found) {

No need to add found flag, we can do if (!debugfs_path) here instead.

> +		char *tmpdir = tst_tmpdir_path();
> +		debugfs_path = malloc(PATH_MAX);
> +		if (!debugfs_path)
> +			tst_brk(TBROK | TERRNO, "malloc failed");
> +		snprintf(debugfs_path, PATH_MAX, "%s/debugfs", tmpdir);

This could be single line with SAFE_ASPRINTF()

> +		SAFE_MKDIR(debugfs_path, 0755);
> +		SAFE_MOUNT("debugfs", debugfs_path, "debugfs", 0, NULL);
> +		debugfs_mounted_by_us = 1;
> +	}
> +
> +	/* Set tracing path */
> +	tracing_path = malloc(PATH_MAX);
> +	if (!tracing_path)
> +		tst_brk(TBROK | TERRNO, "malloc failed");
> +
> +	snprintf(tracing_path, PATH_MAX, "%s/tracing", debugfs_path);

This can be SAFE_ASPRINTF() as well.


> +	/* Check if tracing is supported */
> +	if (access(tracing_path, F_OK) != 0)
> +		tst_brk(TCONF, "Tracing is not supported");
> +
> +	/* Save current settings */
> +	ftrace_save_settings();
> +}
> +
> +void ftrace_cleanup(void)
> +{
> +	ftrace_restore_settings();
> +
> +	if (debugfs_mounted_by_us && debugfs_path) {
> +		tst_umount(debugfs_path);
> +		rmdir(debugfs_path);
> +	}
> +
> +	free(tracing_path);
> +	free(debugfs_path);
> +
> +	/* Free saved state */
> +	free(saved_state.trace_options);
> +	free(saved_state.tracing_on);
> +	free(saved_state.buffer_size);
> +	free(saved_state.tracing_cpumask);
> +	free(saved_state.tracing_enabled);
> +	free(saved_state.stack_tracer_enabled);
> +	free(saved_state.ftrace_enabled);
> +	free(saved_state.function_profile_enabled);
> +}
> +
> +char *ftrace_get_path(const char *filename)
> +{
> +	char *path;
> +
> +	path = malloc(PATH_MAX);
> +	if (!path)
> +		return NULL;
> +
> +	snprintf(path, PATH_MAX, "%s/%s", tracing_path, filename);

SAFE_ASPRINTF() here as well.

> +	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;
> +
> +	/* Read entire file */
> +	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);

This could be replaced by single SAFE_FILE_PRINTF()

> +	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")) {
> +		char *path = strdup("/proc/sys/kernel/stack_tracer_enabled");
> +		FILE *fp = fopen(path, "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);
> +		}
> +		free(path);
> +	}
> +
> +	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;
> +
> +	/* Reset tracer and events */
> +	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);
> +
> +	/* Restore trace options */
> +	if (saved_state.trace_options) {
> +		char *options = strdup(saved_state.trace_options);
> +		char *token = strtok(options, "\n");
> +		while (token) {
> +			ftrace_write_file("trace_options", token);
> +			token = strtok(NULL, "\n");
> +		}
> +		free(options);
> +	}
> +
> +	/* Clear trace */
> +	ftrace_clear_trace();
> +
> +	/* Clear filter */
> +	if (ftrace_file_exists("set_ftrace_filter"))
> +		ftrace_write_file("set_ftrace_filter", "\n");
> +}
> +
> +char **ftrace_get_available_tracers(int *count)
> +{
> +	char *content;
> +	char **tracers = NULL;
> +	int n = 0;
> +	char *token;
> +	char *saveptr;
> +
> +	content = ftrace_read_file("available_tracers");
> +	if (!content) {
> +		*count = 0;
> +		return NULL;
> +	}
> +
> +	/* Count tracers */
> +	char *tmp = strdup(content);
> +	token = strtok_r(tmp, " \n", &saveptr);
> +	while (token) {
> +		n++;
> +		token = strtok_r(NULL, " \n", &saveptr);
> +	}
> +	free(tmp);
> +
> +	/* Allocate array */
> +	tracers = malloc(sizeof(char *) * n);
> +	if (!tracers) {
> +		free(content);
> +		*count = 0;
> +		return NULL;
> +	}
> +
> +	/* Fill array */
> +	n = 0;
> +	token = strtok_r(content, " \n", &saveptr);
> +	while (token) {
> +		tracers[n++] = strdup(token);
> +		token = strtok_r(NULL, " \n", &saveptr);
> +	}
> +
> +	free(content);
> +	*count = n;
> +	return tracers;

This would be much easier if you just read the file line by line

	f = SAFE_FOPEN(...)

	while (fgets(line, sizeof(line), f) {
		...
	}

	SAFE_FCLOSE(f);

> +}
> +
> +int ftrace_set_tracer(const char *tracer)
> +{
> +	char buf[256];
> +	snprintf(buf, sizeof(buf), "%s\n", tracer);
> +	return ftrace_write_file("current_tracer", buf);
> +}
> +
> +void ftrace_clear_trace(void)
> +{
> +	ftrace_write_file("trace", "\n");
> +}
> +
> +void ftrace_enable_tracing(void)
> +{
> +	ftrace_write_file("tracing_on", "1\n");
> +}
> +
> +void ftrace_disable_tracing(void)
> +{
> +	ftrace_write_file("tracing_on", "0\n");
> +}

Generally it would make sense to keep the paths to these files in a
global variables, set then only once in the init and then we could just
do:

void ftrace_set_tracer(const char *tracer)
{
	SAFE_FILE_PRINTF(path_ftrace_tracer, "%s", tracer);
}

> 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..b40877ed1
> --- /dev/null
> +++ b/testcases/kernel/tracing/ftrace_test/ftrace_lib.h
> @@ -0,0 +1,139 @@
> +/* 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>
> +
> +/* Global paths */
> +extern char *tracing_path;
> +extern char *debugfs_path;
> +
> +/* Saved settings for cleanup */
> +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;
> +

Why is this leaking into the tests? None of these low level details
should be exposed since you are building a library for the tests to use.

> +/**
> + * ftrace_initialize() - Initialize ftrace test environment
> + *
> + * This function:
> + * - Checks if debugfs is mounted, mounts it if needed
> + * - Verifies tracing support
> + * - Saves current ftrace settings

We use kernel doc comments that are parsed and exported into
documentation.

https://docs.kernel.org/doc-guide/kernel-doc.html

> + */
> +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
> + *
> + * Returns: 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
> + *
> + * Returns: 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
> + *
> + * Returns: 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
> + *
> + * Returns: 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
> + *
> + * Returns: 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
> + *
> + * Returns: 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
> 
> -- 
> Mailing list info: https://lists.linux.it/listinfo/ltp

-- 
Cyril Hrubis
chrubis@suse.cz

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

  parent reply	other threads:[~2026-06-08  9:41 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-08  5:49 [LTP] [LTP PATCH v4 0/5] ftrace: Convert shell tests to C Praveen K Pandey
2026-06-08  5:49 ` [LTP] [LTP PATCH v4 1/5] ftrace: Add common library for C implementation Praveen K Pandey
2026-06-08  9:01   ` [LTP] " linuxtestproject.agent
2026-06-08  9:41   ` Cyril Hrubis [this message]
2026-06-08  5:49 ` [LTP] [LTP PATCH v4 2/5] ftrace: Convert ftrace_regression01.sh to C Praveen K Pandey
2026-06-08  5:49 ` [LTP] [LTP PATCH v4 3/5] ftrace: Convert ftrace_regression02.sh " Praveen K Pandey
2026-06-08  5:49 ` [LTP] [LTP PATCH v4 4/5] ftrace: Convert ftrace_stress_test.sh " Praveen K Pandey
2026-06-08  5:50 ` [LTP] [LTP PATCH v4 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=aiaOSb3OCJRd1Qry@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.