blob: fb03b2fd06025f811b9e7e9cd9a961d16f75570d [file] [log] [blame]
From Aaditya.Kumar@ap.sony.com Fri Nov 23 03:50:07 2012
From: Aaditya Kumar <aaditya.kumar@ap.sony.com>
Date: Fri, 23 Nov 2012 17:14:25 +0530
Subject: [PATCH v2 RESEND 13/15] AXFS: XIP debugging support.
To: Greg KH <gregkh@linuxfoundation.org>
Cc: "ltsi-dev@lists.linuxfoundation.org" <ltsi-dev@lists.linuxfoundation.org>, tim.bird@am.sony.com, frank.rowand@am.sony.com, takuzo.ohara@ap.sony.com, amit.agarwal@ap.sony.com, kan.iibuchi@jp.sony.com, aaditya.kumar.30@gmail.com
Message-ID: <50AF6199.7040801@ap.sony.com>
From: Takuzo Ohara <Takuzo.Ohara@ap.sony.com>
This code augments debugg infrastructure for AXFS.
It captures access of XIP mapped pages of files in a
proc entry at /proc/axfs_xip.
Signed-off-by: Takuzo Ohara <Takuzo.Ohara@ap.sony.com>
Signed-off-by: Aaditya Kumar <aaditya.kumar@ap.sony.com>
---
fs/axfs/Kconfig | 18 +++++
fs/axfs/Makefile | 2
fs/axfs/axfs_inode.c | 35 +++++++++-
fs/axfs/axfs_super.c | 4 -
fs/axfs/axfs_xip_profile.c | 154 +++++++++++++++++++++++++++++++++++++++++++++
include/linux/axfs_fs.h | 7 ++
6 files changed, 216 insertions(+), 4 deletions(-)
create mode 100644 fs/axfs/axfs_xip_profile.c
--- a/fs/axfs/Kconfig
+++ b/fs/axfs/Kconfig
@@ -16,3 +16,21 @@ config AXFS_PROFILING
Profiling tooling used to identify what pages in the filesystem
image are actually accessed and how much.
+config AXFS_DEBUG
+ bool "AXFS debugging support"
+ depends on AXFS
+ help
+ If you are experiencing any problems with the AXFS filesystem, say
+ Y here. This will create a profile entry at /proc/axfs_xip. In this
+ profile, the XIP mapped pages of files are recorded.
+
+ If unsure, say N.
+
+config AXFS_DEBUG_XIP_RECORDS_NUM
+ int "Number of axfs xip profile records (100 - 1000)"
+ range 100 1000
+ depends on AXFS_DEBUG
+ default 500
+ help
+ The number of records which /porc/axfs_xip can record. one record
+ takes about 64 bytes of memory.
--- a/fs/axfs/Makefile
+++ b/fs/axfs/Makefile
@@ -6,3 +6,5 @@ obj-$(CONFIG_AXFS) += axfs.o
axfs-y := axfs_inode.o axfs_super.o axfs_uncompress.o axfs_profiling.o \
axfs_uml.o axfs_mtd.o axfs_bdev.o axfs_physmem.o
+
+obj-$(CONFIG_AXFS_DEBUG) += axfs_xip_profile.o
--- a/fs/axfs/axfs_inode.c
+++ b/fs/axfs/axfs_inode.c
@@ -464,6 +464,10 @@ static int axfs_fault(struct vm_area_str
struct axfs_super *sbi = AXFS_SB(sb);
u64 ino_number = inode->i_ino;
u64 array_index;
+#ifdef CONFIG_AXFS_DEBUG
+ unsigned long xip_node_address, offset, length;
+ unsigned int numpages, count;
+#endif
array_index = axfs_get_inode_array_index(sbi, ino_number) + vmf->pgoff;
@@ -474,12 +478,39 @@ static int axfs_fault(struct vm_area_str
if (!(vma->vm_flags & VM_WRITE))
axfs_profiling_add(sbi, array_index, ino_number);
+#ifdef CONFIG_AXFS_DEBUG
+ offset = vma->vm_pgoff;
+ length = vma->vm_end - vma->vm_start;
+
+ if (length > inode->i_size)
+ length = inode->i_size;
+
+ length = PAGE_ALIGN(length);
+ numpages = length >> PAGE_SHIFT;
+#endif
+
/*
* figure out if the node is XIP or compressed and call the
* appropriate function
*/
- if (axfs_is_node_xip(sbi, array_index))
- return xip_file_fault(vma, vmf);
+#ifdef CONFIG_AXFS_DEBUG
+ for (count = 0; count < numpages; count++, array_index++) {
+#endif
+ if (axfs_is_node_xip(sbi, array_index)) {
+#ifdef CONFIG_AXFS_DEBUG
+ xip_node_address = axfs_get_xip_region_physaddr(sbi);
+ xip_node_address += ((axfs_get_inode_num_entries(sbi, array_index)) << PAGE_SHIFT);
+ axfs_xip_record((unsigned char *)file->f_dentry->d_name.name,
+ xip_node_address,
+ vma->vm_start + (PAGE_SIZE * count),
+ (unsigned int)(PAGE_SIZE),
+ pgprot_val(vma->vm_page_prot));
+#endif
+ return xip_file_fault(vma, vmf);
+ }
+#ifdef CONFIG_AXFS_DEBUG
+ }
+#endif
return filemap_fault(vma, vmf);
}
--- a/fs/axfs/axfs_super.c
+++ b/fs/axfs/axfs_super.c
@@ -681,11 +681,11 @@ static int axfs_do_fill_super(struct sup
goto out;
}
+#ifdef CONFIG_AXFS_DEBUG
if (axfs_get_inode_num_entries(sbi, 0) == 0) {
printk(KERN_INFO "axfs: empty filesystem\n");
- err = -EINVAL;
- goto out;
}
+#endif
err = axfs_init_cblock_buffers(sbi);
if (err)
--- /dev/null
+++ b/fs/axfs/axfs_xip_profile.c
@@ -0,0 +1,154 @@
+/*
+ * fs/axfs/axfs_xip_profile.c
+ *
+ * profiler: /proc/axfs_xip
+ *
+ * Copyright 2005-2007 Sony Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ *
+ */
+
+#ifdef CONFIG_AXFS_DEBUG
+
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+
+
+#ifndef CONFIG_AXFS_DEBUG_XIP_RECORDS_NUM
+#define CONFIG_AXFS_DEBUG_XIP_RECORDS_NUM 500
+#endif
+
+#define RECORDS CONFIG_AXFS_DEBUG_XIP_RECORDS_NUM
+
+#define MAX_FILE_NAME_LEN 48
+
+static DEFINE_SEMAPHORE(record_index_sem);
+
+/* each record is 64 bytes */
+struct axfs_xip_record {
+ char filename[MAX_FILE_NAME_LEN]; /* XIP mapped file name */
+ unsigned long physaddr; /* XIP mapped physaddr */
+ unsigned long virtaddr; /* XIP mapped virtaddr */
+ unsigned int size; /* XIP mapped size */
+ unsigned long pgprot; /* XIP mapped page prot */
+};
+
+static struct axfs_xip_record axfs_xip_records[RECORDS];
+static unsigned long record_index;
+
+/* record function */
+int axfs_xip_record(unsigned char *name, unsigned long physaddr,
+ unsigned long virtaddr, unsigned int size,
+ unsigned long pgprot)
+{
+
+ int namelen = 0;
+ if (down_interruptible(&record_index_sem))
+ return -EINTR;
+
+ if (record_index >= RECORDS)
+ goto out;
+
+ axfs_xip_records[record_index].physaddr = physaddr;
+ axfs_xip_records[record_index].virtaddr = virtaddr;
+ axfs_xip_records[record_index].size = size;
+ axfs_xip_records[record_index].pgprot = pgprot;
+ memset(axfs_xip_records[record_index].filename, 0, MAX_FILE_NAME_LEN);
+ namelen = strlen(name);
+ strncpy(axfs_xip_records[record_index].filename, name,
+ (namelen >= MAX_FILE_NAME_LEN) ? MAX_FILE_NAME_LEN-1 : namelen);
+
+ record_index++;
+
+out:
+ up(&record_index_sem);
+ return 0;
+}
+
+static int axfs_xip_record_to_string(struct axfs_xip_record *record,
+ char *buf, int len)
+{
+
+ return snprintf(buf, len,
+ "0x%08lx to 0x%08lx 0x%x 0x%lx %s\n",
+ record->physaddr, record->virtaddr,
+ record->size, record->pgprot, record->filename) ;
+}
+
+
+static unsigned int is_first_line = 1;
+#define PROFILE_HEADINGS "\nXIP: physaddr, virtaddr, size, pgprot, filename\n"
+#define HEADINGS_LEN sizeof(PROFILE_HEADINGS)
+
+static int axfs_xip_proc_read(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ unsigned long tlen = 0;
+ unsigned long index = record_index;
+ struct axfs_xip_record *record;
+
+ if (down_interruptible(&record_index_sem))
+ return -EINTR;
+
+ if (off >= index) {
+ *eof = 1;
+ is_first_line = 1;
+ goto out;
+ }
+ record = &axfs_xip_records[off];
+
+ if (is_first_line) {
+ strncpy(page+tlen, PROFILE_HEADINGS, HEADINGS_LEN);
+ tlen += HEADINGS_LEN - 1;
+ is_first_line = 0;
+ }
+ tlen += axfs_xip_record_to_string(record, page+tlen, PAGE_SIZE-tlen);
+ *start = (char *)1;
+ out:
+ up(&record_index_sem);
+ return tlen > count ? 0 : tlen;
+}
+
+/* Write to Clear */
+static int axfs_xip_proc_write(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ if (down_interruptible(&record_index_sem))
+ return -EINTR;
+
+ record_index = 0;
+
+ up(&record_index_sem);
+ return count;
+}
+
+static int __init axfs_xip_proc_profile(void)
+{
+ struct proc_dir_entry *ent;
+ ent = create_proc_entry("axfs_xip", S_IFREG|S_IRUGO|S_IWUSR, NULL);
+ if (!ent) {
+ printk(KERN_ERR "create axfs_xip proc entry failed\n");
+ return -ENOMEM;
+ }
+ ent->read_proc = axfs_xip_proc_read;
+ ent->write_proc = axfs_xip_proc_write;
+ return 0;
+}
+late_initcall(axfs_xip_proc_profile);
+
+#endif /* CONFIG_AXFS_DEBUG */
--- a/include/linux/axfs_fs.h
+++ b/include/linux/axfs_fs.h
@@ -42,6 +42,13 @@ int axfs_uncompress_block(void *, int, v
int axfs_uncompress_init(void);
int axfs_uncompress_exit(void);
+#ifdef CONFIG_AXFS_DEBUG
+int axfs_xip_record(unsigned char *name, unsigned long physaddr,
+ unsigned long virtaddr,
+ unsigned int size,
+ unsigned long pgprot);
+#endif
+
struct axfs_profiling_data {
u64 inode_number;
unsigned long count;