* [PATCH] more procfs bits for !CONFIG_MMU
@ 2003-01-01 23:05 Christoph Hellwig
2003-01-01 23:43 ` Linus Torvalds
0 siblings, 1 reply; 9+ messages in thread
From: Christoph Hellwig @ 2003-01-01 23:05 UTC (permalink / raw)
To: torvalds; +Cc: linux-kernel
Some file in /proc/<pid>/ need to be generated very differently for
CONFIG_MMU set or not.
To avoid ifdef hell I extented the task_foo() abstraction already
present in array.c a bit and the actual implementations now live
in task_mmu.c and task_nommu.c.
--- 1.4/fs/proc/Makefile Sat Dec 14 07:38:56 2002
+++ edited/fs/proc/Makefile Wed Jan 1 13:45:28 2003
@@ -9,6 +9,12 @@
proc-objs := inode.o root.o base.o generic.o array.o \
kmsg.o proc_tty.o proc_misc.o kcore.o
+ifeq ($(CONFIG_MMU),y)
+proc-objs += task_mmu.o
+else
+proc-objs += task_nommu.o
+endif
+
ifeq ($(CONFIG_PROC_DEVICETREE),y)
proc-objs += proc_devtree.o
endif
--- 1.36/fs/proc/array.c Tue Dec 17 18:07:37 2002
+++ edited/fs/proc/array.c Wed Jan 1 13:46:00 2003
@@ -179,47 +179,6 @@
return buffer;
}
-static inline char * task_mem(struct mm_struct *mm, char *buffer)
-{
- struct vm_area_struct * vma;
- unsigned long data = 0, stack = 0;
- unsigned long exec = 0, lib = 0;
-
- down_read(&mm->mmap_sem);
- for (vma = mm->mmap; vma; vma = vma->vm_next) {
- unsigned long len = (vma->vm_end - vma->vm_start) >> 10;
- if (!vma->vm_file) {
- data += len;
- if (vma->vm_flags & VM_GROWSDOWN)
- stack += len;
- continue;
- }
- if (vma->vm_flags & VM_WRITE)
- continue;
- if (vma->vm_flags & VM_EXEC) {
- exec += len;
- if (vma->vm_flags & VM_EXECUTABLE)
- continue;
- lib += len;
- }
- }
- buffer += sprintf(buffer,
- "VmSize:\t%8lu kB\n"
- "VmLck:\t%8lu kB\n"
- "VmRSS:\t%8lu kB\n"
- "VmData:\t%8lu kB\n"
- "VmStk:\t%8lu kB\n"
- "VmExe:\t%8lu kB\n"
- "VmLib:\t%8lu kB\n",
- mm->total_vm << (PAGE_SHIFT-10),
- mm->locked_vm << (PAGE_SHIFT-10),
- mm->rss << (PAGE_SHIFT-10),
- data - stack, stack,
- exec - lib, lib);
- up_read(&mm->mmap_sem);
- return buffer;
-}
-
static void collect_sigign_sigcatch(struct task_struct *p, sigset_t *ign,
sigset_t *catch)
{
@@ -276,7 +235,7 @@
cap_t(p->cap_effective));
}
-
+extern char *task_mem(struct mm_struct *, char *);
int proc_pid_status(struct task_struct *task, char * buffer)
{
char * orig = buffer;
@@ -297,6 +256,7 @@
return buffer - orig;
}
+extern unsigned long task_vsize(struct mm_struct *);
int proc_pid_stat(struct task_struct *task, char * buffer)
{
unsigned long vsize, eip, esp, wchan;
@@ -320,13 +280,8 @@
}
task_unlock(task);
if (mm) {
- struct vm_area_struct *vma;
down_read(&mm->mmap_sem);
- vma = mm->mmap;
- while (vma) {
- vsize += vma->vm_end - vma->vm_start;
- vma = vma->vm_next;
- }
+ vsize = task_vsize(mm);
eip = KSTK_EIP(task);
esp = KSTK_ESP(task);
up_read(&mm->mmap_sem);
@@ -396,206 +351,21 @@
mmput(mm);
return res;
}
-
-int proc_pid_statm(task_t *task, char *buffer)
-{
- int size, resident, shared, text, lib, data, dirty;
- struct mm_struct *mm = get_task_mm(task);
- struct vm_area_struct * vma;
-
- size = resident = shared = text = lib = data = dirty = 0;
-
- if (!mm)
- goto out;
- down_read(&mm->mmap_sem);
- resident = mm->rss;
- for (vma = mm->mmap; vma; vma = vma->vm_next) {
- int pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
-
- size += pages;
- if (is_vm_hugetlb_page(vma)) {
- if (!(vma->vm_flags & VM_DONTCOPY))
- shared += pages;
- continue;
- }
- if (vma->vm_flags & VM_SHARED || !list_empty(&vma->shared))
- shared += pages;
- if (vma->vm_flags & VM_EXECUTABLE)
- text += pages;
- else
- data += pages;
- }
- up_read(&mm->mmap_sem);
- mmput(mm);
-out:
- return sprintf(buffer,"%d %d %d %d %d %d %d\n",
- size, resident, shared, text, lib, data, dirty);
-}
-
-/*
- * The way we support synthetic files > 4K
- * - without storing their contents in some buffer and
- * - without walking through the entire synthetic file until we reach the
- * position of the requested data
- * is to cleverly encode the current position in the file's f_pos field.
- * There is no requirement that a read() call which returns `count' bytes
- * of data increases f_pos by exactly `count'.
- *
- * This idea is Linus' one. Bruno implemented it.
- */
-
-/*
- * For the /proc/<pid>/maps file, we use fixed length records, each containing
- * a single line.
- *
- * f_pos = (number of the vma in the task->mm->mmap list) * PAGE_SIZE
- * + (index into the line)
- */
-/* for systems with sizeof(void*) == 4: */
-#define MAPS_LINE_FORMAT4 "%08lx-%08lx %s %08lx %02x:%02x %lu"
-#define MAPS_LINE_MAX4 49 /* sum of 8 1 8 1 4 1 8 1 5 1 10 1 */
-
-/* for systems with sizeof(void*) == 8: */
-#define MAPS_LINE_FORMAT8 "%016lx-%016lx %s %016lx %02x:%02x %lu"
-#define MAPS_LINE_MAX8 73 /* sum of 16 1 16 1 4 1 16 1 5 1 10 1 */
-
-#define MAPS_LINE_FORMAT (sizeof(void*) == 4 ? MAPS_LINE_FORMAT4 : MAPS_LINE_FORMAT8)
-#define MAPS_LINE_MAX (sizeof(void*) == 4 ? MAPS_LINE_MAX4 : MAPS_LINE_MAX8)
-
-static int proc_pid_maps_get_line (char *buf, struct vm_area_struct *map)
-{
- /* produce the next line */
- char *line;
- char str[5];
- int flags;
- dev_t dev;
- unsigned long ino;
- int len;
-
- flags = map->vm_flags;
-
- str[0] = flags & VM_READ ? 'r' : '-';
- str[1] = flags & VM_WRITE ? 'w' : '-';
- str[2] = flags & VM_EXEC ? 'x' : '-';
- str[3] = flags & VM_MAYSHARE ? 's' : 'p';
- str[4] = 0;
-
- dev = 0;
- ino = 0;
- if (map->vm_file != NULL) {
- struct inode *inode = map->vm_file->f_dentry->d_inode;
- dev = inode->i_sb->s_dev;
- ino = inode->i_ino;
- line = d_path(map->vm_file->f_dentry,
- map->vm_file->f_vfsmnt,
- buf, PAGE_SIZE);
- buf[PAGE_SIZE-1] = '\n';
- line -= MAPS_LINE_MAX;
- if(line < buf)
- line = buf;
- } else
- line = buf;
-
- len = sprintf(line,
- MAPS_LINE_FORMAT,
- map->vm_start, map->vm_end, str, map->vm_pgoff << PAGE_SHIFT,
- MAJOR(dev), MINOR(dev), ino);
-
- if(map->vm_file) {
- int i;
- for(i = len; i < MAPS_LINE_MAX; i++)
- line[i] = ' ';
- len = buf + PAGE_SIZE - line;
- memmove(buf, line, len);
- } else
- line[len++] = '\n';
- return len;
-}
-
-#ifdef CONFIG_MMU
-ssize_t proc_pid_read_maps(struct task_struct *task, struct file *file,
- char *buf, size_t count, loff_t *ppos)
+extern int task_statm(struct mm_struct *, int *, int *, int *, int *);
+int proc_pid_statm(struct task_struct *task, char *buffer)
{
- struct mm_struct *mm;
- struct vm_area_struct * map;
- char *tmp, *kbuf;
- long retval;
- int off, lineno, loff;
-
- /* reject calls with out of range parameters immediately */
- retval = 0;
- if (*ppos > LONG_MAX)
- goto out;
- if (count == 0)
- goto out;
- off = (long)*ppos;
- /*
- * We might sleep getting the page, so get it first.
- */
- retval = -ENOMEM;
- kbuf = (char*)__get_free_page(GFP_KERNEL);
- if (!kbuf)
- goto out;
-
- tmp = (char*)__get_free_page(GFP_KERNEL);
- if (!tmp)
- goto out_free1;
+ int size = 0, resident = 0, shared = 0, text = 0, lib = 0, data = 0;
+ struct mm_struct *mm = get_task_mm(task);
+
+ if (mm) {
+ down_read(&mm->mmap_sem);
+ size = task_statm(mm, &shared, &text, &data, &resident);
+ up_read(&mm->mmap_sem);
- mm = get_task_mm(task);
-
- retval = 0;
- if (!mm)
- goto out_free2;
-
- down_read(&mm->mmap_sem);
- map = mm->mmap;
- lineno = 0;
- loff = 0;
- if (count > PAGE_SIZE)
- count = PAGE_SIZE;
- while (map) {
- int len;
- if (off > PAGE_SIZE) {
- off -= PAGE_SIZE;
- goto next;
- }
- len = proc_pid_maps_get_line(tmp, map);
- len -= off;
- if (len > 0) {
- if (retval+len > count) {
- /* only partial line transfer possible */
- len = count - retval;
- /* save the offset where the next read
- * must start */
- loff = len+off;
- }
- memcpy(kbuf+retval, tmp+off, len);
- retval += len;
- }
- off = 0;
-next:
- if (!loff)
- lineno++;
- if (retval >= count)
- break;
- if (loff) BUG();
- map = map->vm_next;
+ mmput(mm);
}
- up_read(&mm->mmap_sem);
- mmput(mm);
- if (retval > count) BUG();
- if (copy_to_user(buf, kbuf, retval))
- retval = -EFAULT;
- else
- *ppos = (lineno << PAGE_SHIFT) + loff;
-
-out_free2:
- free_page((unsigned long)tmp);
-out_free1:
- free_page((unsigned long)kbuf);
-out:
- return retval;
+ return sprintf(buffer,"%d %d %d %d %d %d %d\n",
+ size, resident, shared, text, lib, data, 0);
}
-#endif /* CONFIG_MMU */
--- /dev/null 2002-08-30 19:31:37.000000000 -0400
+++ b/fs/proc/task_mmu.c 2003-01-01 13:48:44.000000000 -0500
@@ -0,0 +1,247 @@
+
+#include <linux/mm.h>
+#include <linux/hugetlb.h>
+#include <asm/uaccess.h>
+
+char *task_mem(struct mm_struct *mm, char *buffer)
+{
+ unsigned long data = 0, stack = 0, exec = 0, lib = 0;
+ struct vm_area_struct *vma;
+
+ down_read(&mm->mmap_sem);
+ for (vma = mm->mmap; vma; vma = vma->vm_next) {
+ unsigned long len = (vma->vm_end - vma->vm_start) >> 10;
+ if (!vma->vm_file) {
+ data += len;
+ if (vma->vm_flags & VM_GROWSDOWN)
+ stack += len;
+ continue;
+ }
+ if (vma->vm_flags & VM_WRITE)
+ continue;
+ if (vma->vm_flags & VM_EXEC) {
+ exec += len;
+ if (vma->vm_flags & VM_EXECUTABLE)
+ continue;
+ lib += len;
+ }
+ }
+ buffer += sprintf(buffer,
+ "VmSize:\t%8lu kB\n"
+ "VmLck:\t%8lu kB\n"
+ "VmRSS:\t%8lu kB\n"
+ "VmData:\t%8lu kB\n"
+ "VmStk:\t%8lu kB\n"
+ "VmExe:\t%8lu kB\n"
+ "VmLib:\t%8lu kB\n",
+ mm->total_vm << (PAGE_SHIFT-10),
+ mm->locked_vm << (PAGE_SHIFT-10),
+ mm->rss << (PAGE_SHIFT-10),
+ data - stack, stack,
+ exec - lib, lib);
+ up_read(&mm->mmap_sem);
+ return buffer;
+}
+
+unsigned long task_vsize(struct mm_struct *mm)
+{
+ struct vm_area_struct *vma;
+ unsigned long vsize = 0;
+
+ for (vma = mm->mmap; vma; vma = vma->vm_next)
+ vsize += vma->vm_end - vma->vm_start;
+
+ return vsize;
+}
+
+int task_statm(struct mm_struct *mm, int *shared, int *text,
+ int *data, int *resident)
+{
+ struct vm_area_struct *vma;
+ int size = 0;
+
+ *resident = mm->rss;
+ for (vma = mm->mmap; vma; vma = vma->vm_next) {
+ int pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+
+ size += pages;
+ if (is_vm_hugetlb_page(vma)) {
+ if (!(vma->vm_flags & VM_DONTCOPY))
+ *shared += pages;
+ continue;
+ }
+ if (vma->vm_flags & VM_SHARED || !list_empty(&vma->shared))
+ *shared += pages;
+ if (vma->vm_flags & VM_EXECUTABLE)
+ *text += pages;
+ else
+ *data += pages;
+ }
+
+ return size;
+}
+
+/*
+ * The way we support synthetic files > 4K
+ * - without storing their contents in some buffer and
+ * - without walking through the entire synthetic file until we reach the
+ * position of the requested data
+ * is to cleverly encode the current position in the file's f_pos field.
+ * There is no requirement that a read() call which returns `count' bytes
+ * of data increases f_pos by exactly `count'.
+ *
+ * This idea is Linus' one. Bruno implemented it.
+ */
+
+/*
+ * For the /proc/<pid>/maps file, we use fixed length records, each containing
+ * a single line.
+ *
+ * f_pos = (number of the vma in the task->mm->mmap list) * PAGE_SIZE
+ * + (index into the line)
+ */
+/* for systems with sizeof(void*) == 4: */
+#define MAPS_LINE_FORMAT4 "%08lx-%08lx %s %08lx %02x:%02x %lu"
+#define MAPS_LINE_MAX4 49 /* sum of 8 1 8 1 4 1 8 1 5 1 10 1 */
+
+/* for systems with sizeof(void*) == 8: */
+#define MAPS_LINE_FORMAT8 "%016lx-%016lx %s %016lx %02x:%02x %lu"
+#define MAPS_LINE_MAX8 73 /* sum of 16 1 16 1 4 1 16 1 5 1 10 1 */
+
+#define MAPS_LINE_FORMAT (sizeof(void*) == 4 ? MAPS_LINE_FORMAT4 : MAPS_LINE_FORMAT8)
+#define MAPS_LINE_MAX (sizeof(void*) == 4 ? MAPS_LINE_MAX4 : MAPS_LINE_MAX8)
+
+static int proc_pid_maps_get_line (char *buf, struct vm_area_struct *map)
+{
+ /* produce the next line */
+ char *line;
+ char str[5];
+ int flags;
+ dev_t dev;
+ unsigned long ino;
+ int len;
+
+ flags = map->vm_flags;
+
+ str[0] = flags & VM_READ ? 'r' : '-';
+ str[1] = flags & VM_WRITE ? 'w' : '-';
+ str[2] = flags & VM_EXEC ? 'x' : '-';
+ str[3] = flags & VM_MAYSHARE ? 's' : 'p';
+ str[4] = 0;
+
+ dev = 0;
+ ino = 0;
+ if (map->vm_file != NULL) {
+ struct inode *inode = map->vm_file->f_dentry->d_inode;
+ dev = inode->i_sb->s_dev;
+ ino = inode->i_ino;
+ line = d_path(map->vm_file->f_dentry,
+ map->vm_file->f_vfsmnt,
+ buf, PAGE_SIZE);
+ buf[PAGE_SIZE-1] = '\n';
+ line -= MAPS_LINE_MAX;
+ if(line < buf)
+ line = buf;
+ } else
+ line = buf;
+
+ len = sprintf(line,
+ MAPS_LINE_FORMAT,
+ map->vm_start, map->vm_end, str, map->vm_pgoff << PAGE_SHIFT,
+ MAJOR(dev), MINOR(dev), ino);
+
+ if(map->vm_file) {
+ int i;
+ for(i = len; i < MAPS_LINE_MAX; i++)
+ line[i] = ' ';
+ len = buf + PAGE_SIZE - line;
+ memmove(buf, line, len);
+ } else
+ line[len++] = '\n';
+ return len;
+}
+
+ssize_t proc_pid_read_maps(struct task_struct *task, struct file *file,
+ char *buf, size_t count, loff_t *ppos)
+{
+ struct mm_struct *mm;
+ struct vm_area_struct * map;
+ char *tmp, *kbuf;
+ long retval;
+ int off, lineno, loff;
+
+ /* reject calls with out of range parameters immediately */
+ retval = 0;
+ if (*ppos > LONG_MAX)
+ goto out;
+ if (count == 0)
+ goto out;
+ off = (long)*ppos;
+ /*
+ * We might sleep getting the page, so get it first.
+ */
+ retval = -ENOMEM;
+ kbuf = (char*)__get_free_page(GFP_KERNEL);
+ if (!kbuf)
+ goto out;
+
+ tmp = (char*)__get_free_page(GFP_KERNEL);
+ if (!tmp)
+ goto out_free1;
+
+ mm = get_task_mm(task);
+
+ retval = 0;
+ if (!mm)
+ goto out_free2;
+
+ down_read(&mm->mmap_sem);
+ map = mm->mmap;
+ lineno = 0;
+ loff = 0;
+ if (count > PAGE_SIZE)
+ count = PAGE_SIZE;
+ while (map) {
+ int len;
+ if (off > PAGE_SIZE) {
+ off -= PAGE_SIZE;
+ goto next;
+ }
+ len = proc_pid_maps_get_line(tmp, map);
+ len -= off;
+ if (len > 0) {
+ if (retval+len > count) {
+ /* only partial line transfer possible */
+ len = count - retval;
+ /* save the offset where the next read
+ * must start */
+ loff = len+off;
+ }
+ memcpy(kbuf+retval, tmp+off, len);
+ retval += len;
+ }
+ off = 0;
+next:
+ if (!loff)
+ lineno++;
+ if (retval >= count)
+ break;
+ if (loff) BUG();
+ map = map->vm_next;
+ }
+ up_read(&mm->mmap_sem);
+ mmput(mm);
+
+ if (retval > count) BUG();
+ if (copy_to_user(buf, kbuf, retval))
+ retval = -EFAULT;
+ else
+ *ppos = (lineno << PAGE_SHIFT) + loff;
+
+out_free2:
+ free_page((unsigned long)tmp);
+out_free1:
+ free_page((unsigned long)kbuf);
+out:
+ return retval;
+}
--- /dev/null 2002-08-30 19:31:37.000000000 -0400
+++ b/fs/proc/task_nommu.c 2003-01-01 13:51:22.000000000 -0500
@@ -0,0 +1,97 @@
+
+#include <linux/mm.h>
+
+/*
+ * Logic: we've got two memory sums for each process, "shared", and
+ * "non-shared". Shared memory may get counted more then once, for
+ * each process that owns it. Non-shared memory is counted
+ * accurately.
+ */
+char *task_mem(struct mm_struct *mm, char *buffer)
+{
+ unsigned long bytes = 0, sbytes = 0, slack = 0;
+ struct mm_tblock_struct *tblock;
+
+ down_read(&mm->mmap_sem);
+ for (tblock = &mm->context.tblock; tblock; tblock = tblock->next) {
+ if (!tblock->rblock)
+ continue;
+ bytes += kobjsize(tblock);
+ if (atomic_read(&mm->mm_count) > 1 ||
+ tblock->rblock->refcount > 1) {
+ sbytes += kobjsize(tblock->rblock->kblock);
+ sbytes += kobjsize(tblock->rblock);
+ } else {
+ bytes += kobjsize(tblock->rblock->kblock);
+ bytes += kobjsize(tblock->rblock);
+ slack += kobjsize(tblock->rblock->kblock) -
+ tblock->rblock->size;
+ }
+ }
+
+ if (atomic_read(&mm->mm_count) > 1)
+ sbytes += kobjsize(mm);
+ else
+ bytes += kobjsize(mm);
+
+ if (current->fs && atomic_read(¤t->fs->count) > 1)
+ sbytes += kobjsize(current->fs);
+ else
+ bytes += kobjsize(current->fs);
+
+ if (current->files && atomic_read(¤t->files->count) > 1)
+ sbytes += kobjsize(current->files);
+ else
+ bytes += kobjsize(current->files);
+
+ if (current->sig && atomic_read(¤t->sig->count) > 1)
+ sbytes += kobjsize(current->sig);
+ else
+ bytes += kobjsize(current->sig);
+
+ bytes += kobjsize(current); /* includes kernel stack */
+
+ buffer += sprintf(buffer,
+ "Mem:\t%8lu bytes\n"
+ "Slack:\t%8lu bytes\n"
+ "Shared:\t%8lu bytes\n",
+ bytes, slack, sbytes);
+
+ up_read(&mm->mmap_sem);
+ return buffer;
+}
+
+unsigned long task_vsize(struct mm_struct *mm)
+{
+ struct mm_tblock_struct *tbp;
+ unsigned long vsize;
+
+ for (tbp = &mm->context.tblock; tbp; tbp = tbp->next) {
+ if (tbp->rblock)
+ vsize += kobjsize(tbp->rblock->kblock);
+ }
+
+ return vsize;
+}
+
+int task_statm(struct mm_struct *mm, int *shared, int *text,
+ int *data, int *resident)
+{
+ struct mm_tblock_struct *tbp;
+ int size = kobjsize(mm);
+
+ for (tbp = &mm->context.tblock; tbp; tbp = tbp->next) {
+ if (tbp->next)
+ size += kobjsize(tbp->next);
+ if (tbp->rblock) {
+ size += kobjsize(tbp->rblock);
+ size += kobjsize(tbp->rblock->kblock);
+ }
+ }
+
+ size += (text = mm->end_code - mm->start_code);
+ size += (data = mm->start_stack - mm->start_data);
+
+ *resident = size;
+ return size;
+}
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH] more procfs bits for !CONFIG_MMU 2003-01-01 23:05 [PATCH] more procfs bits for !CONFIG_MMU Christoph Hellwig @ 2003-01-01 23:43 ` Linus Torvalds 2003-01-01 23:58 ` Christoph Hellwig 2003-01-15 16:11 ` Christoph Hellwig 0 siblings, 2 replies; 9+ messages in thread From: Linus Torvalds @ 2003-01-01 23:43 UTC (permalink / raw) To: Christoph Hellwig; +Cc: linux-kernel On Thu, 2 Jan 2003, Christoph Hellwig wrote: > > To avoid ifdef hell I extented the task_foo() abstraction already > present in array.c a bit and the actual implementations now live > in task_mmu.c and task_nommu.c. Please do "proc_mmu.c" and "proc_nommu.c", and move the non-task-related parts there too (ie move "pid_maps_read()" there too, and just make the no-mmu version of it be empty or whatever, ok?) That should get rid of the last CONFIG_MMU #ifdef stuff. Also: > --- 1.4/fs/proc/Makefile Sat Dec 14 07:38:56 2002 > +++ edited/fs/proc/Makefile Wed Jan 1 13:45:28 2003 > @@ -9,6 +9,12 @@ > proc-objs := inode.o root.o base.o generic.o array.o \ > kmsg.o proc_tty.o proc_misc.o kcore.o > > +ifeq ($(CONFIG_MMU),y) > +proc-objs += task_mmu.o > +else > +proc-objs += task_nommu.o > +endif Isn't it much nicer to just write this something like proc-mmu-y = proc_mmu.o proc-mmu-n = proc_nommu.o obj-y += $(proc-mmu-$(CONFIG_MMU)) instead, and avoid conditionals? Linus ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] more procfs bits for !CONFIG_MMU 2003-01-01 23:43 ` Linus Torvalds @ 2003-01-01 23:58 ` Christoph Hellwig 2003-01-02 0:32 ` Linus Torvalds 2003-01-02 16:29 ` Sam Ravnborg 2003-01-15 16:11 ` Christoph Hellwig 1 sibling, 2 replies; 9+ messages in thread From: Christoph Hellwig @ 2003-01-01 23:58 UTC (permalink / raw) To: Linus Torvalds; +Cc: Christoph Hellwig, linux-kernel On Wed, Jan 01, 2003 at 03:43:05PM -0800, Linus Torvalds wrote: > > On Thu, 2 Jan 2003, Christoph Hellwig wrote: > > > > To avoid ifdef hell I extented the task_foo() abstraction already > > present in array.c a bit and the actual implementations now live > > in task_mmu.c and task_nommu.c. > > Please do "proc_mmu.c" and "proc_nommu.c", and move the non-task-related > parts there too (ie move "pid_maps_read()" there too, and just make the > no-mmu version of it be empty or whatever, ok?) I can add an empty stub function, but that doesn't help to reduce the ifdef mess as there is no /proc/<pid>/maps on nommu at all so we don't have the struct file_operations and more important can't register it. Maybe I need to make adding new entries for /proc/<pid>/ dynamic so proc_mmu.c can just call create_proc_pid_entry("stats", &proc_maps_operations, ...) > > --- 1.4/fs/proc/Makefile Sat Dec 14 07:38:56 2002 > > +++ edited/fs/proc/Makefile Wed Jan 1 13:45:28 2003 > > @@ -9,6 +9,12 @@ > > proc-objs := inode.o root.o base.o generic.o array.o \ > > kmsg.o proc_tty.o proc_misc.o kcore.o > > > > +ifeq ($(CONFIG_MMU),y) > > +proc-objs += task_mmu.o > > +else > > +proc-objs += task_nommu.o > > +endif > > Isn't it much nicer to just write this something like > > proc-mmu-y = proc_mmu.o > proc-mmu-n = proc_nommu.o > > obj-y += $(proc-mmu-$(CONFIG_MMU)) > > instead, and avoid conditionals? Could be done. Maybe Kai even has an even nicer generic version? :) The new makefiles really need some docs.. ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] more procfs bits for !CONFIG_MMU 2003-01-01 23:58 ` Christoph Hellwig @ 2003-01-02 0:32 ` Linus Torvalds 2003-01-02 16:29 ` Sam Ravnborg 1 sibling, 0 replies; 9+ messages in thread From: Linus Torvalds @ 2003-01-02 0:32 UTC (permalink / raw) To: Christoph Hellwig; +Cc: Christoph Hellwig, linux-kernel On Wed, 1 Jan 2003, Christoph Hellwig wrote: > > I can add an empty stub function, but that doesn't help to reduce the > ifdef mess as there is no /proc/<pid>/maps on nommu at all so we don't > have the struct file_operations and more important can't register it. So change it. I'd rather have an empty /proc/pid/maps than have the general code have #ifdef's. Or make /proc more dynamic, although I don't think it's necessarily worth it unless it would be part of a generic dentry'ification (the devfs work is all well and good, but /proc has been around even longer). Linus ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] more procfs bits for !CONFIG_MMU 2003-01-01 23:58 ` Christoph Hellwig 2003-01-02 0:32 ` Linus Torvalds @ 2003-01-02 16:29 ` Sam Ravnborg 2003-01-02 16:35 ` Christoph Hellwig 1 sibling, 1 reply; 9+ messages in thread From: Sam Ravnborg @ 2003-01-02 16:29 UTC (permalink / raw) To: Christoph Hellwig, Linus Torvalds, Christoph Hellwig, linux-kernel, Kai Germaschewski On Wed, Jan 01, 2003 at 11:58:42PM +0000, Christoph Hellwig wrote: > > Isn't it much nicer to just write this something like > > > > proc-mmu-y = proc_mmu.o > > proc-mmu-n = proc_nommu.o > > > > obj-y += $(proc-mmu-$(CONFIG_MMU)) > > > > instead, and avoid conditionals? > > Could be done. Maybe Kai even has an even nicer generic version? :) Here's my try: Old makefile: proc-objs := inode.o root.o base.o generic.o array.o \ kmsg.o proc_tty.o proc_misc.o kcore.o ifeq ($(CONFIG_PROC_DEVICETREE),y) proc-objs += proc_devtree.o endif New Makefile: proc-y := proc_mmu.o proc-$(CONFIG_MMU) := proc_nommu.o proc-y += inode.o root.o base.o generic.o array.o \ kmsg.o proc_tty.o proc_misc.o kcore.o proc-$(CONFIG_PROC_DEVICETREE) += proc_devtree.o Untested... Sam ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] more procfs bits for !CONFIG_MMU 2003-01-02 16:29 ` Sam Ravnborg @ 2003-01-02 16:35 ` Christoph Hellwig 2003-01-02 16:49 ` Sam Ravnborg 0 siblings, 1 reply; 9+ messages in thread From: Christoph Hellwig @ 2003-01-02 16:35 UTC (permalink / raw) To: Christoph Hellwig, Linus Torvalds, Christoph Hellwig, linux-kernel, Kai Germaschewski On Thu, Jan 02, 2003 at 05:29:56PM +0100, Sam Ravnborg wrote: > New Makefile: > proc-y := proc_mmu.o > proc-$(CONFIG_MMU) := proc_nommu.o > Wouldn't this add proc_mmu.o even if CONFIG_MMU is not y? ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] more procfs bits for !CONFIG_MMU 2003-01-02 16:35 ` Christoph Hellwig @ 2003-01-02 16:49 ` Sam Ravnborg 2003-01-02 16:51 ` Christoph Hellwig 0 siblings, 1 reply; 9+ messages in thread From: Sam Ravnborg @ 2003-01-02 16:49 UTC (permalink / raw) To: Christoph Hellwig, Christoph Hellwig, Linus Torvalds, linux-kernel, Kai Germaschewski On Thu, Jan 02, 2003 at 05:35:05PM +0100, Christoph Hellwig wrote: > On Thu, Jan 02, 2003 at 05:29:56PM +0100, Sam Ravnborg wrote: > > New Makefile: > > proc-y := proc_mmu.o > > proc-$(CONFIG_MMU) := proc_nommu.o > > > > Wouldn't this add proc_mmu.o even if CONFIG_MMU is not y? Ups, you are right. I thought about CONFIG_NOMMU.. Should read: proc-y := proc_nommu.o proc-$(CONFIG_MMU) := proc_mmu.o If CONFIG_MMU is 'y', then the first assignment is overwritten. The same principle (pattern?), but with reversed logic. But this one is not that nice, because the common case overwrite the un-common case. Sam ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] more procfs bits for !CONFIG_MMU 2003-01-02 16:49 ` Sam Ravnborg @ 2003-01-02 16:51 ` Christoph Hellwig 0 siblings, 0 replies; 9+ messages in thread From: Christoph Hellwig @ 2003-01-02 16:51 UTC (permalink / raw) To: Christoph Hellwig, Christoph Hellwig, Linus Torvalds, linux-kernel, Kai Germaschewski On Thu, Jan 02, 2003 at 05:49:14PM +0100, Sam Ravnborg wrote: > Ups, you are right. I thought about CONFIG_NOMMU.. > Should read: > proc-y := proc_nommu.o > proc-$(CONFIG_MMU) := proc_mmu.o > > If CONFIG_MMU is 'y', then the first assignment is overwritten. > > The same principle (pattern?), but with reversed logic. > But this one is not that nice, because the common case overwrite the > un-common case. Yeah. Maybe we should add obj-no-$(CONFIG_FOO) & friends ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] more procfs bits for !CONFIG_MMU 2003-01-01 23:43 ` Linus Torvalds 2003-01-01 23:58 ` Christoph Hellwig @ 2003-01-15 16:11 ` Christoph Hellwig 1 sibling, 0 replies; 9+ messages in thread From: Christoph Hellwig @ 2003-01-15 16:11 UTC (permalink / raw) To: Linus Torvalds; +Cc: Christoph Hellwig, linux-kernel On Wed, Jan 01, 2003 at 03:43:05PM -0800, Linus Torvalds wrote: > > On Thu, 2 Jan 2003, Christoph Hellwig wrote: > > > > To avoid ifdef hell I extented the task_foo() abstraction already > > present in array.c a bit and the actual implementations now live > > in task_mmu.c and task_nommu.c. > > Please do "proc_mmu.c" and "proc_nommu.c", and move the non-task-related > parts there too (ie move "pid_maps_read()" there too, and just make the > no-mmu version of it be empty or whatever, ok?) > > That should get rid of the last CONFIG_MMU #ifdef stuff. New version (without the renaming as everything is still task-related :)), but with all ifdef CONFIG_MMU gone from procfs. The conditionals in the makefile are still in, I'm waiting for a obj-no-$(CONFIG_FOO).. --- 1.4/fs/proc/Makefile Sat Dec 14 13:38:56 2002 +++ edited/fs/proc/Makefile Wed Jan 15 16:46:03 2003 @@ -9,6 +9,12 @@ proc-objs := inode.o root.o base.o generic.o array.o \ kmsg.o proc_tty.o proc_misc.o kcore.o +ifeq ($(CONFIG_MMU),y) +proc-objs += task_mmu.o +else +proc-objs += task_nommu.o +endif + ifeq ($(CONFIG_PROC_DEVICETREE),y) proc-objs += proc_devtree.o endif --- 1.37/fs/proc/array.c Wed Jan 8 13:04:31 2003 +++ edited/fs/proc/array.c Wed Jan 15 16:46:04 2003 @@ -180,47 +180,6 @@ return buffer; } -static inline char * task_mem(struct mm_struct *mm, char *buffer) -{ - struct vm_area_struct * vma; - unsigned long data = 0, stack = 0; - unsigned long exec = 0, lib = 0; - - down_read(&mm->mmap_sem); - for (vma = mm->mmap; vma; vma = vma->vm_next) { - unsigned long len = (vma->vm_end - vma->vm_start) >> 10; - if (!vma->vm_file) { - data += len; - if (vma->vm_flags & VM_GROWSDOWN) - stack += len; - continue; - } - if (vma->vm_flags & VM_WRITE) - continue; - if (vma->vm_flags & VM_EXEC) { - exec += len; - if (vma->vm_flags & VM_EXECUTABLE) - continue; - lib += len; - } - } - buffer += sprintf(buffer, - "VmSize:\t%8lu kB\n" - "VmLck:\t%8lu kB\n" - "VmRSS:\t%8lu kB\n" - "VmData:\t%8lu kB\n" - "VmStk:\t%8lu kB\n" - "VmExe:\t%8lu kB\n" - "VmLib:\t%8lu kB\n", - mm->total_vm << (PAGE_SHIFT-10), - mm->locked_vm << (PAGE_SHIFT-10), - mm->rss << (PAGE_SHIFT-10), - data - stack, stack, - exec - lib, lib); - up_read(&mm->mmap_sem); - return buffer; -} - static void collect_sigign_sigcatch(struct task_struct *p, sigset_t *ign, sigset_t *catch) { @@ -277,7 +236,7 @@ cap_t(p->cap_effective)); } - +extern char *task_mem(struct mm_struct *, char *); int proc_pid_status(struct task_struct *task, char * buffer) { char * orig = buffer; @@ -298,6 +257,7 @@ return buffer - orig; } +extern unsigned long task_vsize(struct mm_struct *); int proc_pid_stat(struct task_struct *task, char * buffer) { unsigned long vsize, eip, esp, wchan; @@ -321,13 +281,8 @@ } task_unlock(task); if (mm) { - struct vm_area_struct *vma; down_read(&mm->mmap_sem); - vma = mm->mmap; - while (vma) { - vsize += vma->vm_end - vma->vm_start; - vma = vma->vm_next; - } + vsize = task_vsize(mm); eip = KSTK_EIP(task); esp = KSTK_ESP(task); up_read(&mm->mmap_sem); @@ -397,206 +352,21 @@ mmput(mm); return res; } - -int proc_pid_statm(task_t *task, char *buffer) -{ - int size, resident, shared, text, lib, data, dirty; - struct mm_struct *mm = get_task_mm(task); - struct vm_area_struct * vma; - - size = resident = shared = text = lib = data = dirty = 0; - - if (!mm) - goto out; - down_read(&mm->mmap_sem); - resident = mm->rss; - for (vma = mm->mmap; vma; vma = vma->vm_next) { - int pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; - - size += pages; - if (is_vm_hugetlb_page(vma)) { - if (!(vma->vm_flags & VM_DONTCOPY)) - shared += pages; - continue; - } - if (vma->vm_flags & VM_SHARED || !list_empty(&vma->shared)) - shared += pages; - if (vma->vm_flags & VM_EXECUTABLE) - text += pages; - else - data += pages; - } - up_read(&mm->mmap_sem); - mmput(mm); -out: - return sprintf(buffer,"%d %d %d %d %d %d %d\n", - size, resident, shared, text, lib, data, dirty); -} - -/* - * The way we support synthetic files > 4K - * - without storing their contents in some buffer and - * - without walking through the entire synthetic file until we reach the - * position of the requested data - * is to cleverly encode the current position in the file's f_pos field. - * There is no requirement that a read() call which returns `count' bytes - * of data increases f_pos by exactly `count'. - * - * This idea is Linus' one. Bruno implemented it. - */ - -/* - * For the /proc/<pid>/maps file, we use fixed length records, each containing - * a single line. - * - * f_pos = (number of the vma in the task->mm->mmap list) * PAGE_SIZE - * + (index into the line) - */ -/* for systems with sizeof(void*) == 4: */ -#define MAPS_LINE_FORMAT4 "%08lx-%08lx %s %08lx %02x:%02x %lu" -#define MAPS_LINE_MAX4 49 /* sum of 8 1 8 1 4 1 8 1 5 1 10 1 */ - -/* for systems with sizeof(void*) == 8: */ -#define MAPS_LINE_FORMAT8 "%016lx-%016lx %s %016lx %02x:%02x %lu" -#define MAPS_LINE_MAX8 73 /* sum of 16 1 16 1 4 1 16 1 5 1 10 1 */ - -#define MAPS_LINE_FORMAT (sizeof(void*) == 4 ? MAPS_LINE_FORMAT4 : MAPS_LINE_FORMAT8) -#define MAPS_LINE_MAX (sizeof(void*) == 4 ? MAPS_LINE_MAX4 : MAPS_LINE_MAX8) - -static int proc_pid_maps_get_line (char *buf, struct vm_area_struct *map) -{ - /* produce the next line */ - char *line; - char str[5]; - int flags; - dev_t dev; - unsigned long ino; - int len; - - flags = map->vm_flags; - - str[0] = flags & VM_READ ? 'r' : '-'; - str[1] = flags & VM_WRITE ? 'w' : '-'; - str[2] = flags & VM_EXEC ? 'x' : '-'; - str[3] = flags & VM_MAYSHARE ? 's' : 'p'; - str[4] = 0; - - dev = 0; - ino = 0; - if (map->vm_file != NULL) { - struct inode *inode = map->vm_file->f_dentry->d_inode; - dev = inode->i_sb->s_dev; - ino = inode->i_ino; - line = d_path(map->vm_file->f_dentry, - map->vm_file->f_vfsmnt, - buf, PAGE_SIZE); - buf[PAGE_SIZE-1] = '\n'; - line -= MAPS_LINE_MAX; - if(line < buf) - line = buf; - } else - line = buf; - - len = sprintf(line, - MAPS_LINE_FORMAT, - map->vm_start, map->vm_end, str, map->vm_pgoff << PAGE_SHIFT, - MAJOR(dev), MINOR(dev), ino); - - if(map->vm_file) { - int i; - for(i = len; i < MAPS_LINE_MAX; i++) - line[i] = ' '; - len = buf + PAGE_SIZE - line; - memmove(buf, line, len); - } else - line[len++] = '\n'; - return len; -} - -#ifdef CONFIG_MMU -ssize_t proc_pid_read_maps(struct task_struct *task, struct file *file, - char *buf, size_t count, loff_t *ppos) +extern int task_statm(struct mm_struct *, int *, int *, int *, int *); +int proc_pid_statm(struct task_struct *task, char *buffer) { - struct mm_struct *mm; - struct vm_area_struct * map; - char *tmp, *kbuf; - long retval; - int off, lineno, loff; - - /* reject calls with out of range parameters immediately */ - retval = 0; - if (*ppos > LONG_MAX) - goto out; - if (count == 0) - goto out; - off = (long)*ppos; - /* - * We might sleep getting the page, so get it first. - */ - retval = -ENOMEM; - kbuf = (char*)__get_free_page(GFP_KERNEL); - if (!kbuf) - goto out; - - tmp = (char*)__get_free_page(GFP_KERNEL); - if (!tmp) - goto out_free1; + int size = 0, resident = 0, shared = 0, text = 0, lib = 0, data = 0; + struct mm_struct *mm = get_task_mm(task); + + if (mm) { + down_read(&mm->mmap_sem); + size = task_statm(mm, &shared, &text, &data, &resident); + up_read(&mm->mmap_sem); - mm = get_task_mm(task); - - retval = 0; - if (!mm) - goto out_free2; - - down_read(&mm->mmap_sem); - map = mm->mmap; - lineno = 0; - loff = 0; - if (count > PAGE_SIZE) - count = PAGE_SIZE; - while (map) { - int len; - if (off > PAGE_SIZE) { - off -= PAGE_SIZE; - goto next; - } - len = proc_pid_maps_get_line(tmp, map); - len -= off; - if (len > 0) { - if (retval+len > count) { - /* only partial line transfer possible */ - len = count - retval; - /* save the offset where the next read - * must start */ - loff = len+off; - } - memcpy(kbuf+retval, tmp+off, len); - retval += len; - } - off = 0; -next: - if (!loff) - lineno++; - if (retval >= count) - break; - if (loff) BUG(); - map = map->vm_next; + mmput(mm); } - up_read(&mm->mmap_sem); - mmput(mm); - if (retval > count) BUG(); - if (copy_to_user(buf, kbuf, retval)) - retval = -EFAULT; - else - *ppos = (lineno << PAGE_SHIFT) + loff; - -out_free2: - free_page((unsigned long)tmp); -out_free1: - free_page((unsigned long)kbuf); -out: - return retval; + return sprintf(buffer,"%d %d %d %d %d %d %d\n", + size, resident, shared, text, lib, data, 0); } -#endif /* CONFIG_MMU */ --- 1.37/fs/proc/base.c Mon Dec 30 08:51:24 2002 +++ edited/fs/proc/base.c Wed Jan 15 17:03:15 2003 @@ -75,9 +75,7 @@ E(PROC_PID_CMDLINE, "cmdline", S_IFREG|S_IRUGO), E(PROC_PID_STAT, "stat", S_IFREG|S_IRUGO), E(PROC_PID_STATM, "statm", S_IFREG|S_IRUGO), -#ifdef CONFIG_MMU E(PROC_PID_MAPS, "maps", S_IFREG|S_IRUGO), -#endif E(PROC_PID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR), E(PROC_PID_CWD, "cwd", S_IFLNK|S_IRWXUGO), E(PROC_PID_ROOT, "root", S_IFLNK|S_IRWXUGO), @@ -323,7 +321,6 @@ return proc_check_root(inode); } -#ifdef CONFIG_MMU extern ssize_t proc_pid_read_maps(struct task_struct *, struct file *, char *, size_t, loff_t *); static ssize_t pid_maps_read(struct file * file, char * buf, @@ -340,7 +337,6 @@ static struct file_operations proc_maps_operations = { .read = pid_maps_read, }; -#endif /* CONFIG_MMU */ extern struct seq_operations mounts_op; static int mounts_open(struct inode *inode, struct file *file) @@ -1029,11 +1025,9 @@ inode->i_fop = &proc_info_file_operations; ei->op.proc_read = proc_pid_statm; break; -#ifdef CONFIG_MMU case PROC_PID_MAPS: inode->i_fop = &proc_maps_operations; break; -#endif case PROC_PID_MEM: inode->i_op = &proc_mem_inode_operations; inode->i_fop = &proc_mem_operations; --- /dev/null Sat Mar 23 20:46:34 2002 +++ a/fs/proc/task_mmu.c Wed Jan 15 16:46:04 2003 @@ -0,0 +1,247 @@ + +#include <linux/mm.h> +#include <linux/hugetlb.h> +#include <asm/uaccess.h> + +char *task_mem(struct mm_struct *mm, char *buffer) +{ + unsigned long data = 0, stack = 0, exec = 0, lib = 0; + struct vm_area_struct *vma; + + down_read(&mm->mmap_sem); + for (vma = mm->mmap; vma; vma = vma->vm_next) { + unsigned long len = (vma->vm_end - vma->vm_start) >> 10; + if (!vma->vm_file) { + data += len; + if (vma->vm_flags & VM_GROWSDOWN) + stack += len; + continue; + } + if (vma->vm_flags & VM_WRITE) + continue; + if (vma->vm_flags & VM_EXEC) { + exec += len; + if (vma->vm_flags & VM_EXECUTABLE) + continue; + lib += len; + } + } + buffer += sprintf(buffer, + "VmSize:\t%8lu kB\n" + "VmLck:\t%8lu kB\n" + "VmRSS:\t%8lu kB\n" + "VmData:\t%8lu kB\n" + "VmStk:\t%8lu kB\n" + "VmExe:\t%8lu kB\n" + "VmLib:\t%8lu kB\n", + mm->total_vm << (PAGE_SHIFT-10), + mm->locked_vm << (PAGE_SHIFT-10), + mm->rss << (PAGE_SHIFT-10), + data - stack, stack, + exec - lib, lib); + up_read(&mm->mmap_sem); + return buffer; +} + +unsigned long task_vsize(struct mm_struct *mm) +{ + struct vm_area_struct *vma; + unsigned long vsize = 0; + + for (vma = mm->mmap; vma; vma = vma->vm_next) + vsize += vma->vm_end - vma->vm_start; + + return vsize; +} + +int task_statm(struct mm_struct *mm, int *shared, int *text, + int *data, int *resident) +{ + struct vm_area_struct *vma; + int size = 0; + + *resident = mm->rss; + for (vma = mm->mmap; vma; vma = vma->vm_next) { + int pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; + + size += pages; + if (is_vm_hugetlb_page(vma)) { + if (!(vma->vm_flags & VM_DONTCOPY)) + *shared += pages; + continue; + } + if (vma->vm_flags & VM_SHARED || !list_empty(&vma->shared)) + *shared += pages; + if (vma->vm_flags & VM_EXECUTABLE) + *text += pages; + else + *data += pages; + } + + return size; +} + +/* + * The way we support synthetic files > 4K + * - without storing their contents in some buffer and + * - without walking through the entire synthetic file until we reach the + * position of the requested data + * is to cleverly encode the current position in the file's f_pos field. + * There is no requirement that a read() call which returns `count' bytes + * of data increases f_pos by exactly `count'. + * + * This idea is Linus' one. Bruno implemented it. + */ + +/* + * For the /proc/<pid>/maps file, we use fixed length records, each containing + * a single line. + * + * f_pos = (number of the vma in the task->mm->mmap list) * PAGE_SIZE + * + (index into the line) + */ +/* for systems with sizeof(void*) == 4: */ +#define MAPS_LINE_FORMAT4 "%08lx-%08lx %s %08lx %02x:%02x %lu" +#define MAPS_LINE_MAX4 49 /* sum of 8 1 8 1 4 1 8 1 5 1 10 1 */ + +/* for systems with sizeof(void*) == 8: */ +#define MAPS_LINE_FORMAT8 "%016lx-%016lx %s %016lx %02x:%02x %lu" +#define MAPS_LINE_MAX8 73 /* sum of 16 1 16 1 4 1 16 1 5 1 10 1 */ + +#define MAPS_LINE_FORMAT (sizeof(void*) == 4 ? MAPS_LINE_FORMAT4 : MAPS_LINE_FORMAT8) +#define MAPS_LINE_MAX (sizeof(void*) == 4 ? MAPS_LINE_MAX4 : MAPS_LINE_MAX8) + +static int proc_pid_maps_get_line (char *buf, struct vm_area_struct *map) +{ + /* produce the next line */ + char *line; + char str[5]; + int flags; + dev_t dev; + unsigned long ino; + int len; + + flags = map->vm_flags; + + str[0] = flags & VM_READ ? 'r' : '-'; + str[1] = flags & VM_WRITE ? 'w' : '-'; + str[2] = flags & VM_EXEC ? 'x' : '-'; + str[3] = flags & VM_MAYSHARE ? 's' : 'p'; + str[4] = 0; + + dev = 0; + ino = 0; + if (map->vm_file != NULL) { + struct inode *inode = map->vm_file->f_dentry->d_inode; + dev = inode->i_sb->s_dev; + ino = inode->i_ino; + line = d_path(map->vm_file->f_dentry, + map->vm_file->f_vfsmnt, + buf, PAGE_SIZE); + buf[PAGE_SIZE-1] = '\n'; + line -= MAPS_LINE_MAX; + if(line < buf) + line = buf; + } else + line = buf; + + len = sprintf(line, + MAPS_LINE_FORMAT, + map->vm_start, map->vm_end, str, map->vm_pgoff << PAGE_SHIFT, + MAJOR(dev), MINOR(dev), ino); + + if(map->vm_file) { + int i; + for(i = len; i < MAPS_LINE_MAX; i++) + line[i] = ' '; + len = buf + PAGE_SIZE - line; + memmove(buf, line, len); + } else + line[len++] = '\n'; + return len; +} + +ssize_t proc_pid_read_maps(struct task_struct *task, struct file *file, + char *buf, size_t count, loff_t *ppos) +{ + struct mm_struct *mm; + struct vm_area_struct * map; + char *tmp, *kbuf; + long retval; + int off, lineno, loff; + + /* reject calls with out of range parameters immediately */ + retval = 0; + if (*ppos > LONG_MAX) + goto out; + if (count == 0) + goto out; + off = (long)*ppos; + /* + * We might sleep getting the page, so get it first. + */ + retval = -ENOMEM; + kbuf = (char*)__get_free_page(GFP_KERNEL); + if (!kbuf) + goto out; + + tmp = (char*)__get_free_page(GFP_KERNEL); + if (!tmp) + goto out_free1; + + mm = get_task_mm(task); + + retval = 0; + if (!mm) + goto out_free2; + + down_read(&mm->mmap_sem); + map = mm->mmap; + lineno = 0; + loff = 0; + if (count > PAGE_SIZE) + count = PAGE_SIZE; + while (map) { + int len; + if (off > PAGE_SIZE) { + off -= PAGE_SIZE; + goto next; + } + len = proc_pid_maps_get_line(tmp, map); + len -= off; + if (len > 0) { + if (retval+len > count) { + /* only partial line transfer possible */ + len = count - retval; + /* save the offset where the next read + * must start */ + loff = len+off; + } + memcpy(kbuf+retval, tmp+off, len); + retval += len; + } + off = 0; +next: + if (!loff) + lineno++; + if (retval >= count) + break; + if (loff) BUG(); + map = map->vm_next; + } + up_read(&mm->mmap_sem); + mmput(mm); + + if (retval > count) BUG(); + if (copy_to_user(buf, kbuf, retval)) + retval = -EFAULT; + else + *ppos = (lineno << PAGE_SHIFT) + loff; + +out_free2: + free_page((unsigned long)tmp); +out_free1: + free_page((unsigned long)kbuf); +out: + return retval; +} --- /dev/null Sat Mar 23 20:46:34 2002 +++ b/fs/proc/task_nommu.c Wed Jan 15 16:49:26 2003 @@ -0,0 +1,107 @@ + +#include <linux/mm.h> + +/* + * Logic: we've got two memory sums for each process, "shared", and + * "non-shared". Shared memory may get counted more then once, for + * each process that owns it. Non-shared memory is counted + * accurately. + */ +char *task_mem(struct mm_struct *mm, char *buffer) +{ + unsigned long bytes = 0, sbytes = 0, slack = 0; + struct mm_tblock_struct *tblock; + + down_read(&mm->mmap_sem); + for (tblock = &mm->context.tblock; tblock; tblock = tblock->next) { + if (!tblock->rblock) + continue; + bytes += kobjsize(tblock); + if (atomic_read(&mm->mm_count) > 1 || + tblock->rblock->refcount > 1) { + sbytes += kobjsize(tblock->rblock->kblock); + sbytes += kobjsize(tblock->rblock); + } else { + bytes += kobjsize(tblock->rblock->kblock); + bytes += kobjsize(tblock->rblock); + slack += kobjsize(tblock->rblock->kblock) - + tblock->rblock->size; + } + } + + if (atomic_read(&mm->mm_count) > 1) + sbytes += kobjsize(mm); + else + bytes += kobjsize(mm); + + if (current->fs && atomic_read(¤t->fs->count) > 1) + sbytes += kobjsize(current->fs); + else + bytes += kobjsize(current->fs); + + if (current->files && atomic_read(¤t->files->count) > 1) + sbytes += kobjsize(current->files); + else + bytes += kobjsize(current->files); + + if (current->sig && atomic_read(¤t->sig->count) > 1) + sbytes += kobjsize(current->sig); + else + bytes += kobjsize(current->sig); + + bytes += kobjsize(current); /* includes kernel stack */ + + buffer += sprintf(buffer, + "Mem:\t%8lu bytes\n" + "Slack:\t%8lu bytes\n" + "Shared:\t%8lu bytes\n", + bytes, slack, sbytes); + + up_read(&mm->mmap_sem); + return buffer; +} + +unsigned long task_vsize(struct mm_struct *mm) +{ + struct mm_tblock_struct *tbp; + unsigned long vsize; + + for (tbp = &mm->context.tblock; tbp; tbp = tbp->next) { + if (tbp->rblock) + vsize += kobjsize(tbp->rblock->kblock); + } + + return vsize; +} + +int task_statm(struct mm_struct *mm, int *shared, int *text, + int *data, int *resident) +{ + struct mm_tblock_struct *tbp; + int size = kobjsize(mm); + + for (tbp = &mm->context.tblock; tbp; tbp = tbp->next) { + if (tbp->next) + size += kobjsize(tbp->next); + if (tbp->rblock) { + size += kobjsize(tbp->rblock); + size += kobjsize(tbp->rblock->kblock); + } + } + + size += (text = mm->end_code - mm->start_code); + size += (data = mm->start_stack - mm->start_data); + + *resident = size; + return size; +} + +/* + * Albert D. Cahalan suggested to fake entries for the traditional + * sections here. This might be worth investigating. + */ +ssize_t proc_pid_read_maps(struct task_struct *task, struct file *file, + char *buf, size_t count, loff_t *ppos) +{ + return 0; +} ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2003-01-15 16:03 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2003-01-01 23:05 [PATCH] more procfs bits for !CONFIG_MMU Christoph Hellwig 2003-01-01 23:43 ` Linus Torvalds 2003-01-01 23:58 ` Christoph Hellwig 2003-01-02 0:32 ` Linus Torvalds 2003-01-02 16:29 ` Sam Ravnborg 2003-01-02 16:35 ` Christoph Hellwig 2003-01-02 16:49 ` Sam Ravnborg 2003-01-02 16:51 ` Christoph Hellwig 2003-01-15 16:11 ` Christoph Hellwig
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox