From: Jared Hulbert <jaredeh@gmail.com>
To: Linux-kernel@vger.kernel.org, linux-embedded@vger.kernel.org,
linux-mtd <linux-mtd@lists.infradead.org>,
"Jörn Engel" <joern@logfs.org>,
tim.bird@AM.SONY.COM, cotte@d
Subject: [PATCH 05/10] AXFS: axfs_profiling.c
Date: Wed, 20 Aug 2008 22:45:28 -0700 [thread overview]
Message-ID: <48AD00F8.1030004@gmail.com> (raw)
Profiling is a fault instrumentation and /proc formating system.
This is used to get an accurate picture of what the pages are actually used.
Using this info the image can be optimized for XIP
Signed-off-by: Jared Hulbert <jaredeh@gmail.com>
---
diff --git a/fs/axfs/axfs_profiling.c b/fs/axfs/axfs_profiling.c
new file mode 100644
index 0000000..30d881c
--- /dev/null
+++ b/fs/axfs/axfs_profiling.c
@@ -0,0 +1,594 @@
+/*
+ * Advanced XIP File System for Linux - AXFS
+ * Readonly, compressed, and XIP filesystem for Linux systems big and small
+ *
+ * Copyright(c) 2008 Numonyx
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * Authors:
+ * Eric Anderson
+ * Jared Hulbert <jaredeh@gmail.com>
+ * Sujaya Srinivasan
+ * Justin Treon
+ *
+ * More info and current contacts at http://axfs.sourceforge.net
+ *
+ * axfs_profiling.c -
+ * Tracks pages of files that enter the page cache. Outputs through a proc
+ * file which generates a comma separated data file with path, page offset,
+ * count of times entered page cache.
+ */
+
+#include <linux/axfs.h>
+#ifdef CONFIG_AXFS_PROFILING
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/proc_fs.h>
+
+#define AXFS_PROC_DIR_NAME "axfs"
+
+struct axfs_profiling_manager {
+ struct axfs_profiling_data *profiling_data;
+ struct axfs_super *sbi;
+ u32 *dir_structure;
+ u32 size;
+};
+
+#define MAX_STRING_LEN 1024
+
+/* Handles for our Directory and File */
+static struct proc_dir_entry *axfs_proc_dir;
+static u32 proc_name_inc;
+
+/******************************************************************************
+ *
+ * axfs_init_profile_dir_structure
+ *
+ * Description:
+ * Creates the structures for tracking the page usage data and creates the
+ * proc file that will be used to get the data.
+ *
+ * Parameters:
+ * (IN) manager - pointer to the profile manager for the filing system
+ *
+ * (IN) num_inodes - number of files in the system
+ *
+ * Returns:
+ * 0
+ *
+ *****************************************************************************/
+static int axfs_init_profile_dir_structure(struct axfs_profiling_manager
+ *manager, u32 num_inodes)
+{
+
+ struct axfs_super *sbi = (struct axfs_super *)manager->sbi;
+ u32 child_index = 0, i, j;
+ u32 *dir_structure = manager->dir_structure;
+
+ /* loop through each inode in the image and find all
+ of the directories and mark their children */
+ for (i = 0; i < num_inodes; i++) {
+ /* determine if the entry is a directory */
+ if (!S_ISDIR(AXFS_GET_MODE(sbi, i)))
+ continue;
+
+ /* get the index number for this directory */
+ child_index = AXFS_GET_INODE_ARRAY_INDEX(sbi, i);
+
+ /* get the offset to its children */
+ for (j = 0; j < AXFS_GET_INODE_NUM_ENTRIES(sbi, i); j++) {
+ if (dir_structure[child_index + j] != 0) {
+ printk(KERN_ERR
+ "axfs: ERROR inode was already set old "
+ "%lu new %lu\n", (unsigned long)
+ dir_structure[child_index + j],
+ (unsigned long)i);
+ }
+ dir_structure[child_index + j] = i;
+ }
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * axfs_get_directory_path
+ *
+ * Description:
+ * Determines the directory path of every file for printing the spreadsheet.
+ *
+ * Parameters:
+ * (IN) manager - Pointer to axfs profile manager
+ *
+ * (OUT) buffer - Pointer to the printable directory path for each file
+ *
+ * (IN) inode_number - Inode number of file to look up
+ *
+ * Returns:
+ * Size of the path to the file
+ *
+ *
+ **************************************************************************/
+static int axfs_get_directory_path(struct axfs_profiling_manager *manager,
+ char *buffer, u32 inode_number)
+{
+ u32 path_depth = 0;
+ u32 path_size = 0;
+ u32 string_len = 0;
+ u32 index = inode_number;
+ u32 dir_number;
+ u8 **path_array = NULL;
+ struct axfs_super *sbi = (struct axfs_super *)manager->sbi;
+ int i;
+
+ /* determine how deep the directory path is and how big the name
+ string will be walk back until the root directory index is found
+ (index 0 is root) */
+ while (manager->dir_structure[index] != 0) {
+ path_depth++;
+ /* set the index to the index of the parent directory */
+ index = manager->dir_structure[index];
+ }
+
+ if (path_depth != 0) {
+ /* create an array that will hold a pointer for each of the
+ directories names */
+ path_array = vmalloc(path_depth * sizeof(*path_array));
+ if (path_array == NULL) {
+ printk(KERN_DEBUG
+ "axfs: directory_path vmalloc failed.\n");
+ goto out;
+ }
+ }
+
+ index = manager->dir_structure[inode_number];
+ for (i = path_depth; i > 0; i--) {
+ /* get the array_index for the directory corresponding to
+ index */
+ dir_number = AXFS_GET_INODE_ARRAY_INDEX(sbi, index);
+
+ /* store a pointer to the name in the array */
+ path_array[(i - 1)] = (u8 *) AXFS_GET_INODE_NAME(sbi, index);
+
+ index = manager->dir_structure[index];
+ }
+
+ /* now print out the directory structure from the begining */
+ string_len = sprintf(buffer, "./");
+ path_size += string_len;
+ for (i = 0; i < path_depth; i++) {
+ buffer = buffer + string_len;
+ string_len = sprintf(buffer, "%s/", (char *)path_array[i]);
+ path_size += string_len;
+ }
+
+ if (path_array != NULL)
+ vfree(path_array);
+
+out:
+ return path_size;
+
+}
+
+static ssize_t axfs_procfile_read(char *buffer,
+ char **buffer_location,
+ off_t offset, int buffer_length, int *eof,
+ void *data)
+{
+ struct axfs_profiling_manager *man;
+ struct axfs_profiling_data *profile;
+ struct axfs_super *sbi;
+ u64 array_index;
+ u64 loop_size, inode_page_offset, node_offset, inode_number;
+ u64 print_len = 0;
+ unsigned long addr;
+ int len = 0;
+ int i;
+ char *buff, *name = NULL;
+
+ man = (struct axfs_profiling_manager *)data;
+ sbi = man->sbi;
+
+ loop_size = man->size / sizeof(*profile);
+
+ /* If all data has been returned set EOF */
+ if (offset >= loop_size) {
+ *eof = 1;
+ return 0;
+ }
+
+ buff = buffer;
+ /* print as much as the buffer can take */
+ for (i = offset; i < loop_size; i++) {
+
+ if ((print_len + MAX_STRING_LEN) > buffer_length)
+ break;
+ /* get the first profile data structure */
+ profile = &(man->profiling_data[i]);
+
+ if (profile->count == 0)
+ continue;
+
+ inode_number = profile->inode_number;
+
+ /* file names can be duplicated so we must print out the path */
+ len = axfs_get_directory_path(man, buff, inode_number);
+
+ print_len += len;
+ buff += len;
+
+ /* get a pointer to the inode name */
+ array_index = AXFS_GET_INODE_ARRAY_INDEX(sbi, inode_number);
+ name = (char *)AXFS_GET_INODE_NAME(sbi, inode_number);
+
+ /* need to convert the page number in the node area to
+ the page number within the file */
+ node_offset = i;
+ /* gives the offset of the node in the node list area
+ then substract that from the */
+ inode_page_offset = node_offset - array_index;
+
+ /* set everything up to print out */
+ addr = (unsigned long)(inode_page_offset * PAGE_SIZE);
+ len = sprintf(buff, "%s,%lu,%lu\n", name, addr, profile->count);
+
+ print_len += len;
+ buff += len;
+ }
+
+ /* return the number of items printed.
+ This will be added to offset and passed back to us */
+ *buffer_location = (char *)(i - offset);
+
+ return print_len;
+}
+
+static ssize_t axfs_procfile_write(struct file *file,
+ const char *buffer, unsigned long count,
+ void *data)
+{
+ struct axfs_profiling_manager *man_ptr =
+ (struct axfs_profiling_manager *)data;
+
+ if ((count >= 2) && (0 == memcmp(buffer, "on", 2))) {
+ man_ptr->sbi->profiling_on = TRUE;
+ } else if ((count >= 3) && (0 == memcmp(buffer, "off", 3))) {
+ man_ptr->sbi->profiling_on = FALSE;
+ } else if ((count >= 5) && (0 == memcmp(buffer, "clear", 5))) {
+ memset(man_ptr->profiling_data, 0, man_ptr->size);
+ } else {
+ printk(KERN_INFO
+ "axfs: Unknown command. Supported options are:\n");
+ printk(KERN_INFO "\t\"on\"\tTurn on profiling\n");
+ printk(KERN_INFO "\t\"off\"\tTurn off profiling\n");
+ printk(KERN_INFO "\t\"clear\"\tClear profiling buffer\n");
+ }
+
+ return count;
+}
+
+static int axfs_create_proc_directory(void)
+{
+ if (axfs_proc_dir == NULL) {
+ axfs_proc_dir = proc_mkdir(AXFS_PROC_DIR_NAME, NULL);
+ if (!axfs_proc_dir) {
+ printk(KERN_WARNING
+ "axfs: Failed to create directory\n");
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+static void axfs_delete_proc_directory(void)
+{
+ /* Determine if there are any directory elements
+ and remove if all of the proc files are removed. */
+ if (axfs_proc_dir != NULL) {
+ if (axfs_proc_dir->subdir == NULL) {
+ remove_proc_entry(AXFS_PROC_DIR_NAME, NULL);
+ axfs_proc_dir = NULL;
+ }
+ }
+}
+
+/******************************************************************************
+ *
+ * axfs_delete_proc_file
+ *
+ * Description:
+ * Will search through the proc directory for the correct proc file,
+ * then delete it
+ *
+ * Parameters:
+ * (IN) sbi- axfs superblock pointer to determine which proc file to remove
+ *
+ * Returns:
+ * The profiling manager pointer for the proc file.
+ *
+ *****************************************************************************/
+static struct axfs_profiling_manager *axfs_delete_proc_file(struct axfs_super
+ *sbi)
+{
+ struct proc_dir_entry *current_proc_file;
+ struct axfs_profiling_manager *manager;
+ void *rv = NULL;
+
+ if (!axfs_proc_dir)
+ return NULL;
+
+ /* Walk through the proc file entries to find the matching sbi */
+ current_proc_file = axfs_proc_dir->subdir;
+
+ while (current_proc_file != NULL) {
+ manager = current_proc_file->data;
+ if (manager == NULL) {
+ printk(KERN_WARNING
+ "axfs: Error removing proc file private "
+ "data was NULL.\n");
+ rv = NULL;
+ break;
+ }
+ if (manager->sbi == sbi) {
+ /* we found the match */
+ remove_proc_entry(current_proc_file->name,
+ axfs_proc_dir);
+ rv = (void *)manager;
+ break;
+ }
+ current_proc_file = axfs_proc_dir->next;
+ }
+ return (struct axfs_profiling_manager *)rv;
+}
+
+/******************************************************************************
+ *
+ * axfs_register_profiling_proc
+ *
+ * Description:
+ * Will register the instance of the proc file for a given volume.
+ *
+ * Parameters:
+ * (IN) manager - Pointer to the profiling manager for the axfs volume
+ *
+ * Returns:
+ * 0 or error number
+ *
+ *****************************************************************************/
+static int axfs_register_profiling_proc(struct axfs_profiling_manager *manager)
+{
+ int rv = 0;
+ struct proc_dir_entry *proc_file;
+ char file_name[20];
+
+ if (!axfs_create_proc_directory()) {
+ rv = -ENOMEM;
+ goto out;
+ }
+
+ sprintf(file_name, "volume%d", proc_name_inc);
+ proc_file = create_proc_entry(file_name, (mode_t) 0644, axfs_proc_dir);
+ if (proc_file == NULL) {
+ remove_proc_entry(file_name, axfs_proc_dir);
+ axfs_delete_proc_directory();
+ rv = -ENOMEM;
+ goto out;
+ }
+
+ proc_name_inc++;
+ proc_file->read_proc = axfs_procfile_read;
+ proc_file->write_proc = axfs_procfile_write;
+ proc_file->owner = THIS_MODULE;
+ proc_file->mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+ proc_file->uid = 0;
+ proc_file->gid = 0;
+ proc_file->data = manager;
+
+ printk(KERN_DEBUG "axfs: Proc entry created\n");
+
+out:
+ return rv;
+}
+
+/******************************************************************************
+ *
+ * axfs_unregister_profiling_proc
+ *
+ * Description:
+ * Will unregister the instance of the proc file for the volume that was
+ * mounted. If this is the last volume mounted then the proc directory
+ * will also be removed.
+ *
+ * Parameters:
+ * (IN) sbi- axfs superblock pointer to determine which proc file to remove
+ *
+ * Returns:
+ * The profiling manager pointer for the proc file.
+ *
+ *****************************************************************************/
+static struct axfs_profiling_manager *axfs_unregister_profiling_proc(struct
+ axfs_super
+ *sbi)
+{
+ struct axfs_profiling_manager *manager;
+ manager = axfs_delete_proc_file(sbi);
+ axfs_delete_proc_directory();
+ return manager;
+}
+
+/******************************************************************************
+ *
+ * axfs_init_profiling
+ *
+ * Description:
+ * Creates the structures for tracking the page usage data and creates the
+ * proc file that will be used to get the data.
+ *
+ * Parameters:
+ * (IN) sbi- axfs superblock pointer
+ *
+ * Returns:
+ * TRUE or FALSE
+ *
+ *****************************************************************************/
+int axfs_init_profiling(struct axfs_super *sbi)
+{
+
+ u32 num_nodes, num_inodes;
+ struct axfs_profiling_manager *manager = NULL;
+ struct axfs_profiling_data *profile_data = NULL;
+ int err = -ENOMEM;
+
+ /* determine the max number of pages in the FS */
+ num_nodes = sbi->blocks;
+ if (!num_nodes)
+ return 0;
+
+ manager = vmalloc(sizeof(*manager));
+ if (!manager)
+ goto out;
+
+ profile_data = vmalloc(num_nodes * sizeof(*profile_data));
+ if (!profile_data)
+ goto out;
+
+ memset(profile_data, 0, num_nodes * sizeof(*profile_data));
+
+ /* determine the max number of inodes in the FS */
+ num_inodes = sbi->files;
+
+ manager->dir_structure = vmalloc(num_inodes * sizeof(u32 *));
+ if (!manager->dir_structure)
+ goto out;
+
+ memset(manager->dir_structure, 0, (num_inodes * sizeof(u32 *)));
+
+ manager->profiling_data = profile_data;
+ manager->size = num_nodes * sizeof(*profile_data);
+ manager->sbi = sbi;
+ sbi->profiling_on = TRUE; /* Turn on profiling by default */
+ sbi->profile_data_ptr = profile_data;
+
+ err = axfs_init_profile_dir_structure(manager, num_inodes);
+ if (err)
+ goto out;
+
+ err = axfs_register_profiling_proc(manager);
+ if (err)
+ goto out;
+
+ return 0;
+
+out:
+ if (manager->dir_structure)
+ vfree(manager->dir_structure);
+ if (profile_data)
+ vfree(profile_data);
+ if (manager)
+ vfree(manager);
+ return err;
+}
+
+/******************************************************************************
+ *
+ * axfs_shutdown_profiling
+ *
+ * Description:
+ * Remove the proc file for this volume and release the memory in the
+ * profiling manager
+ *
+ * Parameters:
+ * (IN) sbi- axfs superblock pointer
+ *
+ * Returns:
+ * TRUE or FALSE
+ *
+ *****************************************************************************/
+int axfs_shutdown_profiling(struct axfs_super *sbi)
+{
+ struct axfs_profiling_manager *manager;
+ /* remove the proc file for this volume and release the memory in the
+ profiling manager */
+
+ if (!sbi)
+ return TRUE;
+
+ if (!sbi->profile_data_ptr)
+ return TRUE;
+
+ manager = axfs_unregister_profiling_proc(sbi);
+
+ if (manager == NULL)
+ return FALSE;
+
+ if (manager->dir_structure)
+ vfree(manager->dir_structure);
+ if (manager->profiling_data)
+ vfree(manager->profiling_data);
+ if (manager)
+ vfree(manager);
+ return TRUE;
+}
+
+/******************************************************************************
+ *
+ * axfs_profiling_add
+ *
+ * Description:
+ * Log when a node is paged into memory by incrementing the count in the
+ * array profile data structure.
+ *
+ * Parameters:
+ * (IN) sbi- axfs superblock pointer
+ *
+ * (IN) array_index - The offset into the nodes table of file (node number)
+ *
+ * (IN) axfs_inode_number - Inode of the node to determine file name later
+ *
+ * Returns:
+ * none
+ *
+ *****************************************************************************/
+void axfs_profiling_add(struct axfs_super *sbi, unsigned long array_index,
+ unsigned int axfs_inode_number)
+{
+ unsigned long addr;
+ struct axfs_profiling_data *profile_data;
+
+ if (sbi->profiling_on != TRUE)
+ return;
+
+ addr = (unsigned long)sbi->profile_data_ptr;
+ addr += array_index * sizeof(*profile_data);
+
+ profile_data = (struct axfs_profiling_data *)addr;
+
+ /* Record the inode number to determine the file name later. */
+ profile_data->inode_number = axfs_inode_number;
+
+ /* Increment the number of times the node has been paged in */
+ profile_data->count++;
+}
+
+#else
+
+int axfs_init_profiling(struct axfs_super *sbi)
+{
+ return 0;
+}
+
+int axfs_shutdown_profiling(struct axfs_super *sbi)
+{
+ return 0;
+}
+
+void axfs_profiling_add(struct axfs_super *sbi, unsigned long array_index,
+ unsigned int axfs_inode_number)
+{
+}
+
+#endif /* CONFIG_AXFS_PROFILING */
WARNING: multiple messages have this Message-ID (diff)
From: Jared Hulbert <jaredeh@gmail.com>
To: Linux-kernel@vger.kernel.org, linux-embedded@vger.kernel.org,
linux-mtd <linux-mtd@lists.infradead.org>,
"Jörn Engel" <joern@logfs.org>,
tim.bird@AM.SONY.COM, cotte@de.ibm.com, nickpiggin@yahoo.com.au
Subject: [PATCH 05/10] AXFS: axfs_profiling.c
Date: Wed, 20 Aug 2008 22:45:28 -0700 [thread overview]
Message-ID: <48AD00F8.1030004@gmail.com> (raw)
Profiling is a fault instrumentation and /proc formating system.
This is used to get an accurate picture of what the pages are actually used.
Using this info the image can be optimized for XIP
Signed-off-by: Jared Hulbert <jaredeh@gmail.com>
---
diff --git a/fs/axfs/axfs_profiling.c b/fs/axfs/axfs_profiling.c
new file mode 100644
index 0000000..30d881c
--- /dev/null
+++ b/fs/axfs/axfs_profiling.c
@@ -0,0 +1,594 @@
+/*
+ * Advanced XIP File System for Linux - AXFS
+ * Readonly, compressed, and XIP filesystem for Linux systems big and small
+ *
+ * Copyright(c) 2008 Numonyx
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * Authors:
+ * Eric Anderson
+ * Jared Hulbert <jaredeh@gmail.com>
+ * Sujaya Srinivasan
+ * Justin Treon
+ *
+ * More info and current contacts at http://axfs.sourceforge.net
+ *
+ * axfs_profiling.c -
+ * Tracks pages of files that enter the page cache. Outputs through a proc
+ * file which generates a comma separated data file with path, page offset,
+ * count of times entered page cache.
+ */
+
+#include <linux/axfs.h>
+#ifdef CONFIG_AXFS_PROFILING
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/proc_fs.h>
+
+#define AXFS_PROC_DIR_NAME "axfs"
+
+struct axfs_profiling_manager {
+ struct axfs_profiling_data *profiling_data;
+ struct axfs_super *sbi;
+ u32 *dir_structure;
+ u32 size;
+};
+
+#define MAX_STRING_LEN 1024
+
+/* Handles for our Directory and File */
+static struct proc_dir_entry *axfs_proc_dir;
+static u32 proc_name_inc;
+
+/******************************************************************************
+ *
+ * axfs_init_profile_dir_structure
+ *
+ * Description:
+ * Creates the structures for tracking the page usage data and creates the
+ * proc file that will be used to get the data.
+ *
+ * Parameters:
+ * (IN) manager - pointer to the profile manager for the filing system
+ *
+ * (IN) num_inodes - number of files in the system
+ *
+ * Returns:
+ * 0
+ *
+ *****************************************************************************/
+static int axfs_init_profile_dir_structure(struct axfs_profiling_manager
+ *manager, u32 num_inodes)
+{
+
+ struct axfs_super *sbi = (struct axfs_super *)manager->sbi;
+ u32 child_index = 0, i, j;
+ u32 *dir_structure = manager->dir_structure;
+
+ /* loop through each inode in the image and find all
+ of the directories and mark their children */
+ for (i = 0; i < num_inodes; i++) {
+ /* determine if the entry is a directory */
+ if (!S_ISDIR(AXFS_GET_MODE(sbi, i)))
+ continue;
+
+ /* get the index number for this directory */
+ child_index = AXFS_GET_INODE_ARRAY_INDEX(sbi, i);
+
+ /* get the offset to its children */
+ for (j = 0; j < AXFS_GET_INODE_NUM_ENTRIES(sbi, i); j++) {
+ if (dir_structure[child_index + j] != 0) {
+ printk(KERN_ERR
+ "axfs: ERROR inode was already set old "
+ "%lu new %lu\n", (unsigned long)
+ dir_structure[child_index + j],
+ (unsigned long)i);
+ }
+ dir_structure[child_index + j] = i;
+ }
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * axfs_get_directory_path
+ *
+ * Description:
+ * Determines the directory path of every file for printing the spreadsheet.
+ *
+ * Parameters:
+ * (IN) manager - Pointer to axfs profile manager
+ *
+ * (OUT) buffer - Pointer to the printable directory path for each file
+ *
+ * (IN) inode_number - Inode number of file to look up
+ *
+ * Returns:
+ * Size of the path to the file
+ *
+ *
+ **************************************************************************/
+static int axfs_get_directory_path(struct axfs_profiling_manager *manager,
+ char *buffer, u32 inode_number)
+{
+ u32 path_depth = 0;
+ u32 path_size = 0;
+ u32 string_len = 0;
+ u32 index = inode_number;
+ u32 dir_number;
+ u8 **path_array = NULL;
+ struct axfs_super *sbi = (struct axfs_super *)manager->sbi;
+ int i;
+
+ /* determine how deep the directory path is and how big the name
+ string will be walk back until the root directory index is found
+ (index 0 is root) */
+ while (manager->dir_structure[index] != 0) {
+ path_depth++;
+ /* set the index to the index of the parent directory */
+ index = manager->dir_structure[index];
+ }
+
+ if (path_depth != 0) {
+ /* create an array that will hold a pointer for each of the
+ directories names */
+ path_array = vmalloc(path_depth * sizeof(*path_array));
+ if (path_array == NULL) {
+ printk(KERN_DEBUG
+ "axfs: directory_path vmalloc failed.\n");
+ goto out;
+ }
+ }
+
+ index = manager->dir_structure[inode_number];
+ for (i = path_depth; i > 0; i--) {
+ /* get the array_index for the directory corresponding to
+ index */
+ dir_number = AXFS_GET_INODE_ARRAY_INDEX(sbi, index);
+
+ /* store a pointer to the name in the array */
+ path_array[(i - 1)] = (u8 *) AXFS_GET_INODE_NAME(sbi, index);
+
+ index = manager->dir_structure[index];
+ }
+
+ /* now print out the directory structure from the begining */
+ string_len = sprintf(buffer, "./");
+ path_size += string_len;
+ for (i = 0; i < path_depth; i++) {
+ buffer = buffer + string_len;
+ string_len = sprintf(buffer, "%s/", (char *)path_array[i]);
+ path_size += string_len;
+ }
+
+ if (path_array != NULL)
+ vfree(path_array);
+
+out:
+ return path_size;
+
+}
+
+static ssize_t axfs_procfile_read(char *buffer,
+ char **buffer_location,
+ off_t offset, int buffer_length, int *eof,
+ void *data)
+{
+ struct axfs_profiling_manager *man;
+ struct axfs_profiling_data *profile;
+ struct axfs_super *sbi;
+ u64 array_index;
+ u64 loop_size, inode_page_offset, node_offset, inode_number;
+ u64 print_len = 0;
+ unsigned long addr;
+ int len = 0;
+ int i;
+ char *buff, *name = NULL;
+
+ man = (struct axfs_profiling_manager *)data;
+ sbi = man->sbi;
+
+ loop_size = man->size / sizeof(*profile);
+
+ /* If all data has been returned set EOF */
+ if (offset >= loop_size) {
+ *eof = 1;
+ return 0;
+ }
+
+ buff = buffer;
+ /* print as much as the buffer can take */
+ for (i = offset; i < loop_size; i++) {
+
+ if ((print_len + MAX_STRING_LEN) > buffer_length)
+ break;
+ /* get the first profile data structure */
+ profile = &(man->profiling_data[i]);
+
+ if (profile->count == 0)
+ continue;
+
+ inode_number = profile->inode_number;
+
+ /* file names can be duplicated so we must print out the path */
+ len = axfs_get_directory_path(man, buff, inode_number);
+
+ print_len += len;
+ buff += len;
+
+ /* get a pointer to the inode name */
+ array_index = AXFS_GET_INODE_ARRAY_INDEX(sbi, inode_number);
+ name = (char *)AXFS_GET_INODE_NAME(sbi, inode_number);
+
+ /* need to convert the page number in the node area to
+ the page number within the file */
+ node_offset = i;
+ /* gives the offset of the node in the node list area
+ then substract that from the */
+ inode_page_offset = node_offset - array_index;
+
+ /* set everything up to print out */
+ addr = (unsigned long)(inode_page_offset * PAGE_SIZE);
+ len = sprintf(buff, "%s,%lu,%lu\n", name, addr, profile->count);
+
+ print_len += len;
+ buff += len;
+ }
+
+ /* return the number of items printed.
+ This will be added to offset and passed back to us */
+ *buffer_location = (char *)(i - offset);
+
+ return print_len;
+}
+
+static ssize_t axfs_procfile_write(struct file *file,
+ const char *buffer, unsigned long count,
+ void *data)
+{
+ struct axfs_profiling_manager *man_ptr =
+ (struct axfs_profiling_manager *)data;
+
+ if ((count >= 2) && (0 == memcmp(buffer, "on", 2))) {
+ man_ptr->sbi->profiling_on = TRUE;
+ } else if ((count >= 3) && (0 == memcmp(buffer, "off", 3))) {
+ man_ptr->sbi->profiling_on = FALSE;
+ } else if ((count >= 5) && (0 == memcmp(buffer, "clear", 5))) {
+ memset(man_ptr->profiling_data, 0, man_ptr->size);
+ } else {
+ printk(KERN_INFO
+ "axfs: Unknown command. Supported options are:\n");
+ printk(KERN_INFO "\t\"on\"\tTurn on profiling\n");
+ printk(KERN_INFO "\t\"off\"\tTurn off profiling\n");
+ printk(KERN_INFO "\t\"clear\"\tClear profiling buffer\n");
+ }
+
+ return count;
+}
+
+static int axfs_create_proc_directory(void)
+{
+ if (axfs_proc_dir == NULL) {
+ axfs_proc_dir = proc_mkdir(AXFS_PROC_DIR_NAME, NULL);
+ if (!axfs_proc_dir) {
+ printk(KERN_WARNING
+ "axfs: Failed to create directory\n");
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+static void axfs_delete_proc_directory(void)
+{
+ /* Determine if there are any directory elements
+ and remove if all of the proc files are removed. */
+ if (axfs_proc_dir != NULL) {
+ if (axfs_proc_dir->subdir == NULL) {
+ remove_proc_entry(AXFS_PROC_DIR_NAME, NULL);
+ axfs_proc_dir = NULL;
+ }
+ }
+}
+
+/******************************************************************************
+ *
+ * axfs_delete_proc_file
+ *
+ * Description:
+ * Will search through the proc directory for the correct proc file,
+ * then delete it
+ *
+ * Parameters:
+ * (IN) sbi- axfs superblock pointer to determine which proc file to remove
+ *
+ * Returns:
+ * The profiling manager pointer for the proc file.
+ *
+ *****************************************************************************/
+static struct axfs_profiling_manager *axfs_delete_proc_file(struct axfs_super
+ *sbi)
+{
+ struct proc_dir_entry *current_proc_file;
+ struct axfs_profiling_manager *manager;
+ void *rv = NULL;
+
+ if (!axfs_proc_dir)
+ return NULL;
+
+ /* Walk through the proc file entries to find the matching sbi */
+ current_proc_file = axfs_proc_dir->subdir;
+
+ while (current_proc_file != NULL) {
+ manager = current_proc_file->data;
+ if (manager == NULL) {
+ printk(KERN_WARNING
+ "axfs: Error removing proc file private "
+ "data was NULL.\n");
+ rv = NULL;
+ break;
+ }
+ if (manager->sbi == sbi) {
+ /* we found the match */
+ remove_proc_entry(current_proc_file->name,
+ axfs_proc_dir);
+ rv = (void *)manager;
+ break;
+ }
+ current_proc_file = axfs_proc_dir->next;
+ }
+ return (struct axfs_profiling_manager *)rv;
+}
+
+/******************************************************************************
+ *
+ * axfs_register_profiling_proc
+ *
+ * Description:
+ * Will register the instance of the proc file for a given volume.
+ *
+ * Parameters:
+ * (IN) manager - Pointer to the profiling manager for the axfs volume
+ *
+ * Returns:
+ * 0 or error number
+ *
+ *****************************************************************************/
+static int axfs_register_profiling_proc(struct axfs_profiling_manager *manager)
+{
+ int rv = 0;
+ struct proc_dir_entry *proc_file;
+ char file_name[20];
+
+ if (!axfs_create_proc_directory()) {
+ rv = -ENOMEM;
+ goto out;
+ }
+
+ sprintf(file_name, "volume%d", proc_name_inc);
+ proc_file = create_proc_entry(file_name, (mode_t) 0644, axfs_proc_dir);
+ if (proc_file == NULL) {
+ remove_proc_entry(file_name, axfs_proc_dir);
+ axfs_delete_proc_directory();
+ rv = -ENOMEM;
+ goto out;
+ }
+
+ proc_name_inc++;
+ proc_file->read_proc = axfs_procfile_read;
+ proc_file->write_proc = axfs_procfile_write;
+ proc_file->owner = THIS_MODULE;
+ proc_file->mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+ proc_file->uid = 0;
+ proc_file->gid = 0;
+ proc_file->data = manager;
+
+ printk(KERN_DEBUG "axfs: Proc entry created\n");
+
+out:
+ return rv;
+}
+
+/******************************************************************************
+ *
+ * axfs_unregister_profiling_proc
+ *
+ * Description:
+ * Will unregister the instance of the proc file for the volume that was
+ * mounted. If this is the last volume mounted then the proc directory
+ * will also be removed.
+ *
+ * Parameters:
+ * (IN) sbi- axfs superblock pointer to determine which proc file to remove
+ *
+ * Returns:
+ * The profiling manager pointer for the proc file.
+ *
+ *****************************************************************************/
+static struct axfs_profiling_manager *axfs_unregister_profiling_proc(struct
+ axfs_super
+ *sbi)
+{
+ struct axfs_profiling_manager *manager;
+ manager = axfs_delete_proc_file(sbi);
+ axfs_delete_proc_directory();
+ return manager;
+}
+
+/******************************************************************************
+ *
+ * axfs_init_profiling
+ *
+ * Description:
+ * Creates the structures for tracking the page usage data and creates the
+ * proc file that will be used to get the data.
+ *
+ * Parameters:
+ * (IN) sbi- axfs superblock pointer
+ *
+ * Returns:
+ * TRUE or FALSE
+ *
+ *****************************************************************************/
+int axfs_init_profiling(struct axfs_super *sbi)
+{
+
+ u32 num_nodes, num_inodes;
+ struct axfs_profiling_manager *manager = NULL;
+ struct axfs_profiling_data *profile_data = NULL;
+ int err = -ENOMEM;
+
+ /* determine the max number of pages in the FS */
+ num_nodes = sbi->blocks;
+ if (!num_nodes)
+ return 0;
+
+ manager = vmalloc(sizeof(*manager));
+ if (!manager)
+ goto out;
+
+ profile_data = vmalloc(num_nodes * sizeof(*profile_data));
+ if (!profile_data)
+ goto out;
+
+ memset(profile_data, 0, num_nodes * sizeof(*profile_data));
+
+ /* determine the max number of inodes in the FS */
+ num_inodes = sbi->files;
+
+ manager->dir_structure = vmalloc(num_inodes * sizeof(u32 *));
+ if (!manager->dir_structure)
+ goto out;
+
+ memset(manager->dir_structure, 0, (num_inodes * sizeof(u32 *)));
+
+ manager->profiling_data = profile_data;
+ manager->size = num_nodes * sizeof(*profile_data);
+ manager->sbi = sbi;
+ sbi->profiling_on = TRUE; /* Turn on profiling by default */
+ sbi->profile_data_ptr = profile_data;
+
+ err = axfs_init_profile_dir_structure(manager, num_inodes);
+ if (err)
+ goto out;
+
+ err = axfs_register_profiling_proc(manager);
+ if (err)
+ goto out;
+
+ return 0;
+
+out:
+ if (manager->dir_structure)
+ vfree(manager->dir_structure);
+ if (profile_data)
+ vfree(profile_data);
+ if (manager)
+ vfree(manager);
+ return err;
+}
+
+/******************************************************************************
+ *
+ * axfs_shutdown_profiling
+ *
+ * Description:
+ * Remove the proc file for this volume and release the memory in the
+ * profiling manager
+ *
+ * Parameters:
+ * (IN) sbi- axfs superblock pointer
+ *
+ * Returns:
+ * TRUE or FALSE
+ *
+ *****************************************************************************/
+int axfs_shutdown_profiling(struct axfs_super *sbi)
+{
+ struct axfs_profiling_manager *manager;
+ /* remove the proc file for this volume and release the memory in the
+ profiling manager */
+
+ if (!sbi)
+ return TRUE;
+
+ if (!sbi->profile_data_ptr)
+ return TRUE;
+
+ manager = axfs_unregister_profiling_proc(sbi);
+
+ if (manager == NULL)
+ return FALSE;
+
+ if (manager->dir_structure)
+ vfree(manager->dir_structure);
+ if (manager->profiling_data)
+ vfree(manager->profiling_data);
+ if (manager)
+ vfree(manager);
+ return TRUE;
+}
+
+/******************************************************************************
+ *
+ * axfs_profiling_add
+ *
+ * Description:
+ * Log when a node is paged into memory by incrementing the count in the
+ * array profile data structure.
+ *
+ * Parameters:
+ * (IN) sbi- axfs superblock pointer
+ *
+ * (IN) array_index - The offset into the nodes table of file (node number)
+ *
+ * (IN) axfs_inode_number - Inode of the node to determine file name later
+ *
+ * Returns:
+ * none
+ *
+ *****************************************************************************/
+void axfs_profiling_add(struct axfs_super *sbi, unsigned long array_index,
+ unsigned int axfs_inode_number)
+{
+ unsigned long addr;
+ struct axfs_profiling_data *profile_data;
+
+ if (sbi->profiling_on != TRUE)
+ return;
+
+ addr = (unsigned long)sbi->profile_data_ptr;
+ addr += array_index * sizeof(*profile_data);
+
+ profile_data = (struct axfs_profiling_data *)addr;
+
+ /* Record the inode number to determine the file name later. */
+ profile_data->inode_number = axfs_inode_number;
+
+ /* Increment the number of times the node has been paged in */
+ profile_data->count++;
+}
+
+#else
+
+int axfs_init_profiling(struct axfs_super *sbi)
+{
+ return 0;
+}
+
+int axfs_shutdown_profiling(struct axfs_super *sbi)
+{
+ return 0;
+}
+
+void axfs_profiling_add(struct axfs_super *sbi, unsigned long array_index,
+ unsigned int axfs_inode_number)
+{
+}
+
+#endif /* CONFIG_AXFS_PROFILING */
next reply other threads:[~2008-08-21 5:45 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-08-21 5:45 Jared Hulbert [this message]
2008-08-21 5:45 ` [PATCH 05/10] AXFS: axfs_profiling.c Jared Hulbert
2008-08-21 8:44 ` Carsten Otte
2008-08-21 8:44 ` Carsten Otte
2008-08-21 8:49 ` David Woodhouse
2008-08-21 8:49 ` David Woodhouse
2008-08-21 10:20 ` Carsten Otte
2008-08-21 10:20 ` Carsten Otte
2008-08-21 11:39 ` Arnd Bergmann
2008-08-21 11:39 ` Arnd Bergmann
2008-08-21 14:55 ` Jared Hulbert
2008-08-21 14:55 ` Jared Hulbert
2008-08-21 15:06 ` Arnd Bergmann
2008-08-21 15:06 ` Arnd Bergmann
2008-08-21 15:17 ` Jared Hulbert
2008-08-21 15:17 ` Jared Hulbert
2008-08-21 15:50 ` Arnd Bergmann
2008-08-21 15:50 ` Arnd Bergmann
2008-08-22 7:26 ` Carsten Otte
2008-08-22 7:26 ` Carsten Otte
2008-08-21 15:18 ` Geert Uytterhoeven
2008-08-21 15:18 ` Geert Uytterhoeven
2008-08-22 20:37 ` Arnd Bergmann
2008-08-22 20:37 ` Arnd Bergmann
2008-08-22 20:37 ` Arnd Bergmann
[not found] ` <200808221840.39206.arnd@arndb.de>
[not found] ` <6934efce0808221037u4548dd00q9ccd67545bfbcc8@mail.gmail.com>
2008-08-22 19:38 ` Arnd Bergmann
2008-08-22 19:38 ` Arnd Bergmann
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=48AD00F8.1030004@gmail.com \
--to=jaredeh@gmail.com \
--cc=Linux-kernel@vger.kernel.org \
--cc=cotte@d \
--cc=joern@logfs.org \
--cc=linux-embedded@vger.kernel.org \
--cc=linux-mtd@lists.infradead.org \
--cc=tim.bird@AM.SONY.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.