forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
perf tools: Add debugfs utility routines for perf
Add routines to locate the debugfs mount point and to manage the mounting and unmounting of the debugfs. Signed-off-by: Clark Williams <[email protected]> Cc: Arnaldo Carvalho de Melo <[email protected]> Cc: Peter Zijlstra <[email protected]> LKML-Reference: <20091101155621.2b3503ee@torg> Signed-off-by: Ingo Molnar <[email protected]>
- Loading branch information
Showing
3 changed files
with
268 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,241 @@ | ||
#include "util.h" | ||
#include "debugfs.h" | ||
#include "cache.h" | ||
|
||
static int debugfs_premounted; | ||
static char debugfs_mountpoint[MAX_PATH+1]; | ||
|
||
static const char *debugfs_known_mountpoints[] = { | ||
"/sys/kernel/debug/", | ||
"/debug/", | ||
0, | ||
}; | ||
|
||
/* use this to force a umount */ | ||
void debugfs_force_cleanup(void) | ||
{ | ||
debugfs_find_mountpoint(); | ||
debugfs_premounted = 0; | ||
debugfs_umount(); | ||
} | ||
|
||
/* construct a full path to a debugfs element */ | ||
int debugfs_make_path(const char *element, char *buffer, int size) | ||
{ | ||
int len; | ||
|
||
if (strlen(debugfs_mountpoint) == 0) { | ||
buffer[0] = '\0'; | ||
return -1; | ||
} | ||
|
||
len = strlen(debugfs_mountpoint) + strlen(element) + 1; | ||
if (len >= size) | ||
return len+1; | ||
|
||
snprintf(buffer, size-1, "%s/%s", debugfs_mountpoint, element); | ||
return 0; | ||
} | ||
|
||
static int debugfs_found; | ||
|
||
/* find the path to the mounted debugfs */ | ||
const char *debugfs_find_mountpoint(void) | ||
{ | ||
const char **ptr; | ||
char type[100]; | ||
FILE *fp; | ||
|
||
if (debugfs_found) | ||
return (const char *) debugfs_mountpoint; | ||
|
||
ptr = debugfs_known_mountpoints; | ||
while (*ptr) { | ||
if (debugfs_valid_mountpoint(*ptr) == 0) { | ||
debugfs_found = 1; | ||
strcpy(debugfs_mountpoint, *ptr); | ||
return debugfs_mountpoint; | ||
} | ||
ptr++; | ||
} | ||
|
||
/* give up and parse /proc/mounts */ | ||
fp = fopen("/proc/mounts", "r"); | ||
if (fp == NULL) | ||
die("Can't open /proc/mounts for read"); | ||
|
||
while (fscanf(fp, "%*s %" | ||
STR(MAX_PATH) | ||
"s %99s %*s %*d %*d\n", | ||
debugfs_mountpoint, type) == 2) { | ||
if (strcmp(type, "debugfs") == 0) | ||
break; | ||
} | ||
fclose(fp); | ||
|
||
if (strcmp(type, "debugfs") != 0) | ||
return NULL; | ||
|
||
debugfs_found = 1; | ||
|
||
return debugfs_mountpoint; | ||
} | ||
|
||
/* verify that a mountpoint is actually a debugfs instance */ | ||
|
||
int debugfs_valid_mountpoint(const char *debugfs) | ||
{ | ||
struct statfs st_fs; | ||
|
||
if (statfs(debugfs, &st_fs) < 0) | ||
return -ENOENT; | ||
else if (st_fs.f_type != (long) DEBUGFS_MAGIC) | ||
return -ENOENT; | ||
|
||
return 0; | ||
} | ||
|
||
|
||
int debugfs_valid_entry(const char *path) | ||
{ | ||
struct stat st; | ||
|
||
if (stat(path, &st)) | ||
return -errno; | ||
|
||
return 0; | ||
} | ||
|
||
/* mount the debugfs somewhere */ | ||
|
||
int debugfs_mount(const char *mountpoint) | ||
{ | ||
char mountcmd[128]; | ||
|
||
/* see if it's already mounted */ | ||
if (debugfs_find_mountpoint()) { | ||
debugfs_premounted = 1; | ||
return 0; | ||
} | ||
|
||
/* if not mounted and no argument */ | ||
if (mountpoint == NULL) { | ||
/* see if environment variable set */ | ||
mountpoint = getenv(PERF_DEBUGFS_ENVIRONMENT); | ||
/* if no environment variable, use default */ | ||
if (mountpoint == NULL) | ||
mountpoint = "/sys/kernel/debug"; | ||
} | ||
|
||
/* save the mountpoint */ | ||
strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint)); | ||
|
||
/* mount it */ | ||
snprintf(mountcmd, sizeof(mountcmd), | ||
"/bin/mount -t debugfs debugfs %s", mountpoint); | ||
return system(mountcmd); | ||
} | ||
|
||
/* umount the debugfs */ | ||
|
||
int debugfs_umount(void) | ||
{ | ||
char umountcmd[128]; | ||
int ret; | ||
|
||
/* if it was already mounted, leave it */ | ||
if (debugfs_premounted) | ||
return 0; | ||
|
||
/* make sure it's a valid mount point */ | ||
ret = debugfs_valid_mountpoint(debugfs_mountpoint); | ||
if (ret) | ||
return ret; | ||
|
||
snprintf(umountcmd, sizeof(umountcmd), | ||
"/bin/umount %s", debugfs_mountpoint); | ||
return system(umountcmd); | ||
} | ||
|
||
int debugfs_write(const char *entry, const char *value) | ||
{ | ||
char path[MAX_PATH+1]; | ||
int ret, count; | ||
int fd; | ||
|
||
/* construct the path */ | ||
snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry); | ||
|
||
/* verify that it exists */ | ||
ret = debugfs_valid_entry(path); | ||
if (ret) | ||
return ret; | ||
|
||
/* get how many chars we're going to write */ | ||
count = strlen(value); | ||
|
||
/* open the debugfs entry */ | ||
fd = open(path, O_RDWR); | ||
if (fd < 0) | ||
return -errno; | ||
|
||
while (count > 0) { | ||
/* write it */ | ||
ret = write(fd, value, count); | ||
if (ret <= 0) { | ||
if (ret == EAGAIN) | ||
continue; | ||
close(fd); | ||
return -errno; | ||
} | ||
count -= ret; | ||
} | ||
|
||
/* close it */ | ||
close(fd); | ||
|
||
/* return success */ | ||
return 0; | ||
} | ||
|
||
/* | ||
* read a debugfs entry | ||
* returns the number of chars read or a negative errno | ||
*/ | ||
int debugfs_read(const char *entry, char *buffer, size_t size) | ||
{ | ||
char path[MAX_PATH+1]; | ||
int ret; | ||
int fd; | ||
|
||
/* construct the path */ | ||
snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry); | ||
|
||
/* verify that it exists */ | ||
ret = debugfs_valid_entry(path); | ||
if (ret) | ||
return ret; | ||
|
||
/* open the debugfs entry */ | ||
fd = open(path, O_RDONLY); | ||
if (fd < 0) | ||
return -errno; | ||
|
||
do { | ||
/* read it */ | ||
ret = read(fd, buffer, size); | ||
if (ret == 0) { | ||
close(fd); | ||
return EOF; | ||
} | ||
} while (ret < 0 && errno == EAGAIN); | ||
|
||
/* close it */ | ||
close(fd); | ||
|
||
/* make *sure* there's a null character at the end */ | ||
buffer[ret] = '\0'; | ||
|
||
/* return the number of chars read */ | ||
return ret; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
#ifndef __DEBUGFS_H__ | ||
#define __DEBUGFS_H__ | ||
|
||
#include <sys/mount.h> | ||
|
||
#ifndef MAX_PATH | ||
# define MAX_PATH 256 | ||
#endif | ||
|
||
#ifndef STR | ||
# define _STR(x) #x | ||
# define STR(x) _STR(x) | ||
#endif | ||
|
||
extern const char *debugfs_find_mountpoint(void); | ||
extern int debugfs_valid_mountpoint(const char *debugfs); | ||
extern int debugfs_valid_entry(const char *path); | ||
extern int debugfs_mount(const char *mountpoint); | ||
extern int debugfs_umount(void); | ||
extern int debugfs_write(const char *entry, const char *value); | ||
extern int debugfs_read(const char *entry, char *buffer, size_t size); | ||
extern void debugfs_force_cleanup(void); | ||
extern int debugfs_make_path(const char *element, char *buffer, int size); | ||
|
||
#endif /* __DEBUGFS_H__ */ |