<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">
From: David Howells &lt;dhowells@redhat.com&gt;

The attached patch splits some memory-related procfs files into MMU and !MMU
versions and places them in separate conditionally-compiled files. A header
file local to the fs/proc/ directory is used to declare functions and the like.

Additionally, a !MMU-only proc file (/proc/maps) is provided so that master VMA
list in a uClinux kernel is viewable.

Signed-Off-By: David Howells &lt;dhowells@redhat.com&gt;
Signed-off-by: Andrew Morton &lt;akpm@osdl.org&gt;
---

 25-akpm/fs/proc/Makefile     |    4 -
 25-akpm/fs/proc/array.c      |    1 
 25-akpm/fs/proc/base.c       |   43 -------------
 25-akpm/fs/proc/internal.h   |   48 ++++++++++++++
 25-akpm/fs/proc/mmu.c        |   67 ++++++++++++++++++++
 25-akpm/fs/proc/nommu.c      |  140 +++++++++++++++++++++++++++++++++++++++++++
 25-akpm/fs/proc/proc_misc.c  |   50 +--------------
 25-akpm/fs/proc/task_mmu.c   |   32 +++++++++
 25-akpm/fs/proc/task_nommu.c |   71 ++++++++++++++++-----
 9 files changed, 350 insertions(+), 106 deletions(-)

diff -puN fs/proc/array.c~frv-procfs-changes-for-nommu-changes fs/proc/array.c
--- 25/fs/proc/array.c~frv-procfs-changes-for-nommu-changes	Mon Nov  8 15:00:53 2004
+++ 25-akpm/fs/proc/array.c	Mon Nov  8 15:00:53 2004
@@ -78,6 +78,7 @@
 #include &lt;asm/pgtable.h&gt;
 #include &lt;asm/io.h&gt;
 #include &lt;asm/processor.h&gt;
+#include "internal.h"
 
 /* Gcc optimizes away "strlen(x)" for constant x */
 #define ADDBUF(buffer, string) \
diff -puN fs/proc/base.c~frv-procfs-changes-for-nommu-changes fs/proc/base.c
--- 25/fs/proc/base.c~frv-procfs-changes-for-nommu-changes	Mon Nov  8 15:00:53 2004
+++ 25-akpm/fs/proc/base.c	Mon Nov  8 15:00:53 2004
@@ -32,6 +32,7 @@
 #include &lt;linux/mount.h&gt;
 #include &lt;linux/security.h&gt;
 #include &lt;linux/ptrace.h&gt;
+#include "internal.h"
 
 /*
  * For hysterical raisins we keep the same inumbers as in the old procfs.
@@ -179,21 +180,6 @@ static struct pid_entry tid_attr_stuff[]
 
 #undef E
 
-static inline struct task_struct *proc_task(struct inode *inode)
-{
-	return PROC_I(inode)-&gt;task;
-}
-
-static inline int proc_type(struct inode *inode)
-{
-	return PROC_I(inode)-&gt;type;
-}
-
-int proc_tid_stat(struct task_struct*,char*);
-int proc_tgid_stat(struct task_struct*,char*);
-int proc_pid_status(struct task_struct*,char*);
-int proc_pid_statm(struct task_struct*,char*);
-
 static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
 {
 	struct task_struct *task = proc_task(inode);
@@ -218,33 +204,6 @@ static int proc_fd_link(struct inode *in
 	return -ENOENT;
 }
 
-static int proc_exe_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
-{
-	struct vm_area_struct * vma;
-	int result = -ENOENT;
-	struct task_struct *task = proc_task(inode);
-	struct mm_struct * mm = get_task_mm(task);
-
-	if (!mm)
-		goto out;
-	down_read(&amp;mm-&gt;mmap_sem);
-	vma = mm-&gt;mmap;
-	while (vma) {
-		if ((vma-&gt;vm_flags &amp; VM_EXECUTABLE) &amp;&amp; 
-		    vma-&gt;vm_file) {
-			*mnt = mntget(vma-&gt;vm_file-&gt;f_vfsmnt);
-			*dentry = dget(vma-&gt;vm_file-&gt;f_dentry);
-			result = 0;
-			break;
-		}
-		vma = vma-&gt;vm_next;
-	}
-	up_read(&amp;mm-&gt;mmap_sem);
-	mmput(mm);
-out:
-	return result;
-}
-
 static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
 {
 	struct fs_struct *fs;
diff -puN /dev/null fs/proc/internal.h
--- /dev/null	Thu Apr 11 07:25:15 2002
+++ 25-akpm/fs/proc/internal.h	Mon Nov  8 15:00:53 2004
@@ -0,0 +1,48 @@
+/* internal.h: internal procfs definitions
+ *
+ * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * 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.
+ */
+
+#include &lt;linux/proc_fs.h&gt;
+
+struct vmalloc_info {
+	unsigned long	used;
+	unsigned long	largest_chunk;
+};
+
+#ifdef CONFIG_MMU
+#define VMALLOC_TOTAL (VMALLOC_END - VMALLOC_START)
+extern void get_vmalloc_info(struct vmalloc_info *vmi);
+#else
+
+#define VMALLOC_TOTAL 0UL
+#define get_vmalloc_info(vmi)			\
+do {						\
+	(vmi)-&gt;used = 0;			\
+	(vmi)-&gt;largest_chunk = 0;		\
+} while(0)
+
+#endif
+
+extern void create_seq_entry(char *name, mode_t mode, struct file_operations *f);
+extern int proc_exe_link(struct inode *, struct dentry **, struct vfsmount **);
+extern int proc_tid_stat(struct task_struct *,  char *);
+extern int proc_tgid_stat(struct task_struct *, char *);
+extern int proc_pid_status(struct task_struct *, char *);
+extern int proc_pid_statm(struct task_struct *, char *);
+
+static inline struct task_struct *proc_task(struct inode *inode)
+{
+	return PROC_I(inode)-&gt;task;
+}
+
+static inline int proc_type(struct inode *inode)
+{
+	return PROC_I(inode)-&gt;type;
+}
diff -puN fs/proc/Makefile~frv-procfs-changes-for-nommu-changes fs/proc/Makefile
--- 25/fs/proc/Makefile~frv-procfs-changes-for-nommu-changes	Mon Nov  8 15:00:53 2004
+++ 25-akpm/fs/proc/Makefile	Mon Nov  8 15:00:53 2004
@@ -4,8 +4,8 @@
 
 obj-$(CONFIG_PROC_FS) += proc.o
 
-proc-y			:= task_nommu.o
-proc-$(CONFIG_MMU)	:= task_mmu.o
+proc-y			:= nommu.o task_nommu.o
+proc-$(CONFIG_MMU)	:= mmu.o task_mmu.o
 
 proc-y       += inode.o root.o base.o generic.o array.o \
 		kmsg.o proc_tty.o proc_misc.o
diff -puN /dev/null fs/proc/mmu.c
--- /dev/null	Thu Apr 11 07:25:15 2002
+++ 25-akpm/fs/proc/mmu.c	Mon Nov  8 15:00:53 2004
@@ -0,0 +1,67 @@
+/* mmu.c: mmu memory info files
+ *
+ * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * 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.
+ */
+
+#include &lt;linux/types.h&gt;
+#include &lt;linux/errno.h&gt;
+#include &lt;linux/time.h&gt;
+#include &lt;linux/kernel.h&gt;
+#include &lt;linux/string.h&gt;
+#include &lt;linux/mman.h&gt;
+#include &lt;linux/proc_fs.h&gt;
+#include &lt;linux/mm.h&gt;
+#include &lt;linux/mmzone.h&gt;
+#include &lt;linux/pagemap.h&gt;
+#include &lt;linux/swap.h&gt;
+#include &lt;linux/slab.h&gt;
+#include &lt;linux/smp.h&gt;
+#include &lt;linux/seq_file.h&gt;
+#include &lt;linux/hugetlb.h&gt;
+#include &lt;linux/vmalloc.h&gt;
+#include &lt;asm/uaccess.h&gt;
+#include &lt;asm/pgtable.h&gt;
+#include &lt;asm/tlb.h&gt;
+#include &lt;asm/div64.h&gt;
+#include "internal.h"
+
+void get_vmalloc_info(struct vmalloc_info *vmi)
+{
+	struct vm_struct *vma;
+	unsigned long free_area_size;
+	unsigned long prev_end;
+
+	vmi-&gt;used = 0;
+
+	if (!vmlist) {
+		vmi-&gt;largest_chunk = VMALLOC_TOTAL;
+	}
+	else {
+		vmi-&gt;largest_chunk = 0;
+
+		prev_end = VMALLOC_START;
+
+		read_lock(&amp;vmlist_lock);
+
+		for (vma = vmlist; vma; vma = vma-&gt;next) {
+			vmi-&gt;used += vma-&gt;size;
+
+			free_area_size = (unsigned long) vma-&gt;addr - prev_end;
+			if (vmi-&gt;largest_chunk &lt; free_area_size)
+				vmi-&gt;largest_chunk = free_area_size;
+
+			prev_end = vma-&gt;size + (unsigned long) vma-&gt;addr;
+		}
+
+		if (VMALLOC_END - prev_end &gt; vmi-&gt;largest_chunk)
+			vmi-&gt;largest_chunk = VMALLOC_END - prev_end;
+
+		read_unlock(&amp;vmlist_lock);
+	}
+}
diff -puN /dev/null fs/proc/nommu.c
--- /dev/null	Thu Apr 11 07:25:15 2002
+++ 25-akpm/fs/proc/nommu.c	Mon Nov  8 15:00:53 2004
@@ -0,0 +1,140 @@
+/* nommu.c: mmu-less memory info files
+ *
+ * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * 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.
+ */
+
+#include &lt;linux/init.h&gt;
+#include &lt;linux/module.h&gt;
+#include &lt;linux/errno.h&gt;
+#include &lt;linux/time.h&gt;
+#include &lt;linux/kernel.h&gt;
+#include &lt;linux/string.h&gt;
+#include &lt;linux/mman.h&gt;
+#include &lt;linux/proc_fs.h&gt;
+#include &lt;linux/mm.h&gt;
+#include &lt;linux/mmzone.h&gt;
+#include &lt;linux/pagemap.h&gt;
+#include &lt;linux/swap.h&gt;
+#include &lt;linux/slab.h&gt;
+#include &lt;linux/smp.h&gt;
+#include &lt;linux/seq_file.h&gt;
+#include &lt;linux/hugetlb.h&gt;
+#include &lt;linux/vmalloc.h&gt;
+#include &lt;asm/uaccess.h&gt;
+#include &lt;asm/pgtable.h&gt;
+#include &lt;asm/tlb.h&gt;
+#include &lt;asm/div64.h&gt;
+#include "internal.h"
+
+/*
+ * display a list of all the VMAs the kernel knows about
+ * - nommu kernals have a single flat list
+ */
+static int nommu_vma_list_show(struct seq_file *m, void *v)
+{
+	struct vm_area_struct *map;
+	unsigned long ino = 0;
+	struct file *file;
+	dev_t dev = 0;
+	int flags, len;
+
+	map = list_entry((struct list_head *) v,
+			 struct vm_area_struct, vm_link);
+
+	flags = map-&gt;vm_flags;
+	file = map-&gt;vm_file;
+
+	if (file) {
+		struct inode *inode = map-&gt;vm_file-&gt;f_dentry-&gt;d_inode;
+		dev = inode-&gt;i_sb-&gt;s_dev;
+		ino = inode-&gt;i_ino;
+	}
+
+	seq_printf(m,
+		   "%08lx-%08lx %c%c%c%c %08lx %02x:%02x %lu %n",
+		   map-&gt;vm_start,
+		   map-&gt;vm_end,
+		   flags &amp; VM_READ ? 'r' : '-',
+		   flags &amp; VM_WRITE ? 'w' : '-',
+		   flags &amp; VM_EXEC ? 'x' : '-',
+		   flags &amp; VM_MAYSHARE ? 's' : 'p',
+		   map-&gt;vm_pgoff &lt;&lt; PAGE_SHIFT,
+		   MAJOR(dev), MINOR(dev), ino, &amp;len);
+
+	if (file) {
+		len = 25 + sizeof(void *) * 6 - len;
+		if (len &lt; 1)
+			len = 1;
+		seq_printf(m, "%*c", len, ' ');
+		seq_path(m, file-&gt;f_vfsmnt, file-&gt;f_dentry, "");
+	}
+
+	seq_putc(m, '\n');
+	return 0;
+}
+
+static void *nommu_vma_list_start(struct seq_file *m, loff_t *_pos)
+{
+	struct list_head *_p;
+	loff_t pos = *_pos;
+	void *next = NULL;
+
+	down_read(&amp;nommu_vma_sem);
+
+	list_for_each(_p, &amp;nommu_vma_list) {
+		if (pos == 0) {
+			next = _p;
+			break;
+		}
+	}
+
+	return next;
+}
+
+static void nommu_vma_list_stop(struct seq_file *m, void *v)
+{
+	up_read(&amp;nommu_vma_sem);
+}
+
+static void *nommu_vma_list_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	struct list_head *_p = v;
+
+	(*pos)++;
+
+	_p = _p-&gt;next;
+	return (_p != &amp;nommu_vma_list) ? _p : NULL;
+}
+
+static struct seq_operations proc_nommu_vma_list_seqop = {
+	.start	= nommu_vma_list_start,
+	.next	= nommu_vma_list_next,
+	.stop	= nommu_vma_list_stop,
+	.show	= nommu_vma_list_show
+};
+
+static int proc_nommu_vma_list_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &amp;proc_nommu_vma_list_seqop);
+}
+
+static struct file_operations proc_nommu_vma_list_operations = {
+	.open    = proc_nommu_vma_list_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = seq_release,
+};
+
+static int __init proc_nommu_init(void)
+{
+	create_seq_entry("maps", S_IRUGO, &amp;proc_nommu_vma_list_operations);
+	return 0;
+}
+
+module_init(proc_nommu_init);
diff -puN fs/proc/proc_misc.c~frv-procfs-changes-for-nommu-changes fs/proc/proc_misc.c
--- 25/fs/proc/proc_misc.c~frv-procfs-changes-for-nommu-changes	Mon Nov  8 15:00:53 2004
+++ 25-akpm/fs/proc/proc_misc.c	Mon Nov  8 15:00:53 2004
@@ -49,6 +49,7 @@
 #include &lt;asm/io.h&gt;
 #include &lt;asm/tlb.h&gt;
 #include &lt;asm/div64.h&gt;
+#include "internal.h"
 
 #define LOAD_INT(x) ((x) &gt;&gt; FSHIFT)
 #define LOAD_FRAC(x) LOAD_INT(((x) &amp; (FIXED_1-1)) * 100)
@@ -95,41 +96,6 @@ static int loadavg_read_proc(char *page,
 	return proc_calc_metrics(page, start, off, count, eof, len);
 }
 
-struct vmalloc_info {
-	unsigned long used;
-	unsigned long largest_chunk;
-};
-
-static struct vmalloc_info get_vmalloc_info(void)
-{
-	unsigned long prev_end = VMALLOC_START;
-	struct vm_struct* vma;
-	struct vmalloc_info vmi;
-	vmi.used = 0;
-
-	read_lock(&amp;vmlist_lock);
-
-	if(!vmlist)
-		vmi.largest_chunk = (VMALLOC_END-VMALLOC_START);
-	else
-		vmi.largest_chunk = 0;
-
-	for (vma = vmlist; vma; vma = vma-&gt;next) {
-		unsigned long free_area_size =
-			(unsigned long)vma-&gt;addr - prev_end;
-		vmi.used += vma-&gt;size;
-		if (vmi.largest_chunk &lt; free_area_size )
-
-			vmi.largest_chunk = free_area_size;
-		prev_end = vma-&gt;size + (unsigned long)vma-&gt;addr;
-	}
-	if(VMALLOC_END-prev_end &gt; vmi.largest_chunk)
-		vmi.largest_chunk = VMALLOC_END-prev_end;
-
-	read_unlock(&amp;vmlist_lock);
-	return vmi;
-}
-
 static int uptime_read_proc(char *page, char **start, off_t off,
 				 int count, int *eof, void *data)
 {
@@ -158,7 +124,6 @@ static int meminfo_read_proc(char *page,
 	unsigned long inactive;
 	unsigned long active;
 	unsigned long free;
-	unsigned long vmtot;
 	unsigned long committed;
 	unsigned long allowed;
 	struct vmalloc_info vmi;
@@ -176,10 +141,7 @@ static int meminfo_read_proc(char *page,
 	allowed = ((totalram_pages - hugetlb_total_pages())
 		* sysctl_overcommit_ratio / 100) + total_swap_pages;
 
-	vmtot = (VMALLOC_END-VMALLOC_START)&gt;&gt;10;
-	vmi = get_vmalloc_info();
-	vmi.used &gt;&gt;= 10;
-	vmi.largest_chunk &gt;&gt;= 10;
+	get_vmalloc_info(&amp;vmi);
 
 	/*
 	 * Tagged format, for easy grepping and expansion.
@@ -228,9 +190,9 @@ static int meminfo_read_proc(char *page,
 		K(allowed),
 		K(committed),
 		K(ps.nr_page_table_pages),
-		vmtot,
-		vmi.used,
-		vmi.largest_chunk
+		VMALLOC_TOTAL &gt;&gt; 10,
+		vmi.used &gt;&gt; 10,
+		vmi.largest_chunk &gt;&gt; 10
 		);
 
 		len += hugetlb_report_meminfo(page + len);
@@ -570,7 +532,7 @@ static struct file_operations proc_sysrq
 
 struct proc_dir_entry *proc_root_kcore;
 
-static void create_seq_entry(char *name, mode_t mode, struct file_operations *f)
+void create_seq_entry(char *name, mode_t mode, struct file_operations *f)
 {
 	struct proc_dir_entry *entry;
 	entry = create_proc_entry(name, mode, NULL);
diff -puN fs/proc/task_mmu.c~frv-procfs-changes-for-nommu-changes fs/proc/task_mmu.c
--- 25/fs/proc/task_mmu.c~frv-procfs-changes-for-nommu-changes	Mon Nov  8 15:00:53 2004
+++ 25-akpm/fs/proc/task_mmu.c	Mon Nov  8 15:00:53 2004
@@ -1,8 +1,10 @@
 #include &lt;linux/mm.h&gt;
 #include &lt;linux/hugetlb.h&gt;
+#include &lt;linux/mount.h&gt;
 #include &lt;linux/seq_file.h&gt;
 #include &lt;asm/elf.h&gt;
 #include &lt;asm/uaccess.h&gt;
+#include "internal.h"
 
 char *task_mem(struct mm_struct *mm, char *buffer)
 {
@@ -45,6 +47,36 @@ int task_statm(struct mm_struct *mm, int
 	return mm-&gt;total_vm;
 }
 
+int proc_exe_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
+{
+	struct vm_area_struct * vma;
+	int result = -ENOENT;
+	struct task_struct *task = proc_task(inode);
+	struct mm_struct * mm = get_task_mm(task);
+
+	if (!mm)
+		goto out;
+	down_read(&amp;mm-&gt;mmap_sem);
+
+	vma = mm-&gt;mmap;
+	while (vma) {
+		if ((vma-&gt;vm_flags &amp; VM_EXECUTABLE) &amp;&amp; vma-&gt;vm_file)
+			break;
+		vma = vma-&gt;vm_next;
+	}
+
+	if (vma) {
+		*mnt = mntget(vma-&gt;vm_file-&gt;f_vfsmnt);
+		*dentry = dget(vma-&gt;vm_file-&gt;f_dentry);
+		result = 0;
+	}
+
+	up_read(&amp;mm-&gt;mmap_sem);
+	mmput(mm);
+out:
+	return result;
+}
+
 static int show_map(struct seq_file *m, void *v)
 {
 	struct vm_area_struct *map = v;
diff -puN fs/proc/task_nommu.c~frv-procfs-changes-for-nommu-changes fs/proc/task_nommu.c
--- 25/fs/proc/task_nommu.c~frv-procfs-changes-for-nommu-changes	Mon Nov  8 15:00:53 2004
+++ 25-akpm/fs/proc/task_nommu.c	Mon Nov  8 15:00:53 2004
@@ -1,7 +1,9 @@
 
 #include &lt;linux/mm.h&gt;
 #include &lt;linux/file.h&gt;
+#include &lt;linux/mount.h&gt;
 #include &lt;linux/seq_file.h&gt;
+#include "internal.h"
 
 /*
  * Logic: we've got two memory sums for each process, "shared", and
@@ -15,19 +17,19 @@ char *task_mem(struct mm_struct *mm, cha
 	struct mm_tblock_struct *tblock;
         
 	down_read(&amp;mm-&gt;mmap_sem);
-	for (tblock = &amp;mm-&gt;context.tblock; tblock; tblock = tblock-&gt;next) {
-		if (!tblock-&gt;rblock)
+	for (tblock = mm-&gt;context.tblock; tblock; tblock = tblock-&gt;next) {
+		if (!tblock-&gt;vma)
 			continue;
 		bytes += kobjsize(tblock);
 		if (atomic_read(&amp;mm-&gt;mm_count) &gt; 1 ||
-		    tblock-&gt;rblock-&gt;refcount &gt; 1) {
-			sbytes += kobjsize(tblock-&gt;rblock-&gt;kblock);
-			sbytes += kobjsize(tblock-&gt;rblock);
+		    atomic_read(&amp;tblock-&gt;vma-&gt;vm_usage) &gt; 1) {
+			sbytes += kobjsize((void *) tblock-&gt;vma-&gt;vm_start);
+			sbytes += kobjsize(tblock-&gt;vma);
 		} else {
-			bytes += kobjsize(tblock-&gt;rblock-&gt;kblock);
-			bytes += kobjsize(tblock-&gt;rblock);
-			slack += kobjsize(tblock-&gt;rblock-&gt;kblock) -
-					tblock-&gt;rblock-&gt;size;
+			bytes += kobjsize((void *) tblock-&gt;vma-&gt;vm_start);
+			bytes += kobjsize(tblock-&gt;vma);
+			slack += kobjsize((void *) tblock-&gt;vma-&gt;vm_start) -
+				(tblock-&gt;vma-&gt;vm_end - tblock-&gt;vma-&gt;vm_start);
 		}
 	}
 
@@ -69,9 +71,9 @@ unsigned long task_vsize(struct mm_struc
 	unsigned long vsize = 0;
 
 	down_read(&amp;mm-&gt;mmap_sem);
-	for (tbp = &amp;mm-&gt;context.tblock; tbp; tbp = tbp-&gt;next) {
-		if (tbp-&gt;rblock)
-			vsize += kobjsize(tbp-&gt;rblock-&gt;kblock);
+	for (tbp = mm-&gt;context.tblock; tbp; tbp = tbp-&gt;next) {
+		if (tbp-&gt;vma)
+			vsize += kobjsize((void *) tbp-&gt;vma-&gt;vm_start);
 	}
 	up_read(&amp;mm-&gt;mmap_sem);
 	return vsize;
@@ -84,12 +86,11 @@ int task_statm(struct mm_struct *mm, int
 	int size = kobjsize(mm);
 
 	down_read(&amp;mm-&gt;mmap_sem);
-	for (tbp = &amp;mm-&gt;context.tblock; tbp; tbp = tbp-&gt;next) {
-		if (tbp-&gt;next)
-			size += kobjsize(tbp-&gt;next);
-		if (tbp-&gt;rblock) {
-			size += kobjsize(tbp-&gt;rblock);
-			size += kobjsize(tbp-&gt;rblock-&gt;kblock);
+	for (tbp = mm-&gt;context.tblock; tbp; tbp = tbp-&gt;next) {
+		size += kobjsize(tbp);
+		if (tbp-&gt;vma) {
+			size += kobjsize(tbp-&gt;vma);
+			size += kobjsize((void *) tbp-&gt;vma-&gt;vm_start);
 		}
 	}
 
@@ -100,6 +101,40 @@ int task_statm(struct mm_struct *mm, int
 	return size;
 }
 
+int proc_exe_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
+{
+	struct mm_tblock_struct *tblock;
+	struct vm_area_struct * vma;
+	int result = -ENOENT;
+	struct task_struct *task = proc_task(inode);
+	struct mm_struct * mm = get_task_mm(task);
+
+	if (!mm)
+		goto out;
+	down_read(&amp;mm-&gt;mmap_sem);
+
+	tblock = mm-&gt;context.tblock;
+	vma = NULL;
+	while (tblock) {
+		if ((tblock-&gt;vma-&gt;vm_flags &amp; VM_EXECUTABLE) &amp;&amp; tblock-&gt;vma-&gt;vm_file) {
+			vma = tblock-&gt;vma;
+			break;
+		}
+		tblock = tblock-&gt;next;
+	}
+
+	if (vma) {
+		*mnt = mntget(vma-&gt;vm_file-&gt;f_vfsmnt);
+		*dentry = dget(vma-&gt;vm_file-&gt;f_dentry);
+		result = 0;
+	}
+
+	up_read(&amp;mm-&gt;mmap_sem);
+	mmput(mm);
+out:
+	return result;
+}
+
 /*
  * Albert D. Cahalan suggested to fake entries for the traditional
  * sections here.  This might be worth investigating.
_
</pre></body></html>