| 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; |