[PATCH 18/20] FRV: procfs changes for nommu changes

From: dhowells
Date: Mon Nov 08 2004 - 10:47:56 EST


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: dhowells@xxxxxxxxxx
---
diffstat nommu-proc-2610rc1mm3.diff
Makefile | 4 -
array.c | 1
base.c | 43 ------------------
internal.h | 48 ++++++++++++++++++++
mmu.c | 67 ++++++++++++++++++++++++++++
nommu.c | 140 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
proc_misc.c | 50 ++-------------------
task_mmu.c | 32 +++++++++++++
task_nommu.c | 71 ++++++++++++++++++++++-------
9 files changed, 350 insertions(+), 106 deletions(-)

diff -uNrp /warthog/kernels/linux-2.6.10-rc1-mm3/fs/proc/array.c linux-2.6.10-rc1-mm3-frv/fs/proc/array.c
--- /warthog/kernels/linux-2.6.10-rc1-mm3/fs/proc/array.c 2004-11-05 13:15:43.000000000 +0000
+++ linux-2.6.10-rc1-mm3-frv/fs/proc/array.c 2004-11-05 14:13:03.809503712 +0000
@@ -79,6 +79,7 @@
#include <asm/pgtable.h>
#include <asm/io.h>
#include <asm/processor.h>
+#include "internal.h"

/* Gcc optimizes away "strlen(x)" for constant x */
#define ADDBUF(buffer, string) \
diff -uNrp /warthog/kernels/linux-2.6.10-rc1-mm3/fs/proc/base.c linux-2.6.10-rc1-mm3-frv/fs/proc/base.c
--- /warthog/kernels/linux-2.6.10-rc1-mm3/fs/proc/base.c 2004-11-05 13:15:43.000000000 +0000
+++ linux-2.6.10-rc1-mm3-frv/fs/proc/base.c 2004-11-05 14:13:03.825502360 +0000
@@ -33,6 +33,7 @@
#include <linux/mount.h>
#include <linux/security.h>
#include <linux/ptrace.h>
+#include "internal.h"

/*
* For hysterical raisins we keep the same inumbers as in the old procfs.
@@ -192,21 +193,6 @@ static struct pid_entry tid_attr_stuff[]

#undef E

-static inline struct task_struct *proc_task(struct inode *inode)
-{
- return PROC_I(inode)->task;
-}
-
-static inline int proc_type(struct inode *inode)
-{
- return PROC_I(inode)->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);
@@ -231,33 +217,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(&mm->mmap_sem);
- vma = mm->mmap;
- while (vma) {
- if ((vma->vm_flags & VM_EXECUTABLE) &&
- vma->vm_file) {
- *mnt = mntget(vma->vm_file->f_vfsmnt);
- *dentry = dget(vma->vm_file->f_dentry);
- result = 0;
- break;
- }
- vma = vma->vm_next;
- }
- up_read(&mm->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 -uNrp /warthog/kernels/linux-2.6.10-rc1-mm3/fs/proc/internal.h linux-2.6.10-rc1-mm3-frv/fs/proc/internal.h
--- /warthog/kernels/linux-2.6.10-rc1-mm3/fs/proc/internal.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10-rc1-mm3-frv/fs/proc/internal.h 2004-11-05 14:13:03.830501938 +0000
@@ -0,0 +1,48 @@
+/* internal.h: internal procfs definitions
+ *
+ * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@xxxxxxxxxx)
+ *
+ * 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 <linux/proc_fs.h>
+
+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)->used = 0; \
+ (vmi)->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)->task;
+}
+
+static inline int proc_type(struct inode *inode)
+{
+ return PROC_I(inode)->type;
+}
diff -uNrp /warthog/kernels/linux-2.6.10-rc1-mm3/fs/proc/Makefile linux-2.6.10-rc1-mm3-frv/fs/proc/Makefile
--- /warthog/kernels/linux-2.6.10-rc1-mm3/fs/proc/Makefile 2004-11-05 13:15:43.000000000 +0000
+++ linux-2.6.10-rc1-mm3-frv/fs/proc/Makefile 2004-11-05 14:13:03.839501178 +0000
@@ -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 -uNrp /warthog/kernels/linux-2.6.10-rc1-mm3/fs/proc/mmu.c linux-2.6.10-rc1-mm3-frv/fs/proc/mmu.c
--- /warthog/kernels/linux-2.6.10-rc1-mm3/fs/proc/mmu.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10-rc1-mm3-frv/fs/proc/mmu.c 2004-11-05 14:13:03.000000000 +0000
@@ -0,0 +1,67 @@
+/* mmu.c: mmu memory info files
+ *
+ * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@xxxxxxxxxx)
+ *
+ * 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 <linux/types.h>
+#include <linux/errno.h>
+#include <linux/time.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/mman.h>
+#include <linux/proc_fs.h>
+#include <linux/mm.h>
+#include <linux/mmzone.h>
+#include <linux/pagemap.h>
+#include <linux/swap.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/seq_file.h>
+#include <linux/hugetlb.h>
+#include <linux/vmalloc.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/tlb.h>
+#include <asm/div64.h>
+#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->used = 0;
+
+ if (!vmlist) {
+ vmi->largest_chunk = VMALLOC_TOTAL;
+ }
+ else {
+ vmi->largest_chunk = 0;
+
+ prev_end = VMALLOC_START;
+
+ read_lock(&vmlist_lock);
+
+ for (vma = vmlist; vma; vma = vma->next) {
+ vmi->used += vma->size;
+
+ free_area_size = (unsigned long) vma->addr - prev_end;
+ if (vmi->largest_chunk < free_area_size)
+ vmi->largest_chunk = free_area_size;
+
+ prev_end = vma->size + (unsigned long) vma->addr;
+ }
+
+ if (VMALLOC_END - prev_end > vmi->largest_chunk)
+ vmi->largest_chunk = VMALLOC_END - prev_end;
+
+ read_unlock(&vmlist_lock);
+ }
+}
diff -uNrp /warthog/kernels/linux-2.6.10-rc1-mm3/fs/proc/nommu.c linux-2.6.10-rc1-mm3-frv/fs/proc/nommu.c
--- /warthog/kernels/linux-2.6.10-rc1-mm3/fs/proc/nommu.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10-rc1-mm3-frv/fs/proc/nommu.c 2004-11-05 14:13:03.000000000 +0000
@@ -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@xxxxxxxxxx)
+ *
+ * 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 <linux/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/time.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/mman.h>
+#include <linux/proc_fs.h>
+#include <linux/mm.h>
+#include <linux/mmzone.h>
+#include <linux/pagemap.h>
+#include <linux/swap.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/seq_file.h>
+#include <linux/hugetlb.h>
+#include <linux/vmalloc.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/tlb.h>
+#include <asm/div64.h>
+#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->vm_flags;
+ file = map->vm_file;
+
+ if (file) {
+ struct inode *inode = map->vm_file->f_dentry->d_inode;
+ dev = inode->i_sb->s_dev;
+ ino = inode->i_ino;
+ }
+
+ seq_printf(m,
+ "%08lx-%08lx %c%c%c%c %08lx %02x:%02x %lu %n",
+ map->vm_start,
+ map->vm_end,
+ flags & VM_READ ? 'r' : '-',
+ flags & VM_WRITE ? 'w' : '-',
+ flags & VM_EXEC ? 'x' : '-',
+ flags & VM_MAYSHARE ? 's' : 'p',
+ map->vm_pgoff << PAGE_SHIFT,
+ MAJOR(dev), MINOR(dev), ino, &len);
+
+ if (file) {
+ len = 25 + sizeof(void *) * 6 - len;
+ if (len < 1)
+ len = 1;
+ seq_printf(m, "%*c", len, ' ');
+ seq_path(m, file->f_vfsmnt, file->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(&nommu_vma_sem);
+
+ list_for_each(_p, &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(&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->next;
+ return (_p != &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, &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, &proc_nommu_vma_list_operations);
+ return 0;
+}
+
+module_init(proc_nommu_init);
diff -uNrp /warthog/kernels/linux-2.6.10-rc1-mm3/fs/proc/proc_misc.c linux-2.6.10-rc1-mm3-frv/fs/proc/proc_misc.c
--- /warthog/kernels/linux-2.6.10-rc1-mm3/fs/proc/proc_misc.c 2004-11-05 13:15:43.000000000 +0000
+++ linux-2.6.10-rc1-mm3-frv/fs/proc/proc_misc.c 2004-11-05 14:13:03.865498982 +0000
@@ -50,6 +50,7 @@
#include <asm/io.h>
#include <asm/tlb.h>
#include <asm/div64.h>
+#include "internal.h"

#define LOAD_INT(x) ((x) >> FSHIFT)
#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
@@ -96,41 +97,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(&vmlist_lock);
-
- if(!vmlist)
- vmi.largest_chunk = (VMALLOC_END-VMALLOC_START);
- else
- vmi.largest_chunk = 0;
-
- for (vma = vmlist; vma; vma = vma->next) {
- unsigned long free_area_size =
- (unsigned long)vma->addr - prev_end;
- vmi.used += vma->size;
- if (vmi.largest_chunk < free_area_size )
-
- vmi.largest_chunk = free_area_size;
- prev_end = vma->size + (unsigned long)vma->addr;
- }
- if(VMALLOC_END-prev_end > vmi.largest_chunk)
- vmi.largest_chunk = VMALLOC_END-prev_end;
-
- read_unlock(&vmlist_lock);
- return vmi;
-}
-
static int uptime_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
@@ -159,7 +125,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;
@@ -177,10 +142,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)>>10;
- vmi = get_vmalloc_info();
- vmi.used >>= 10;
- vmi.largest_chunk >>= 10;
+ get_vmalloc_info(&vmi);

/*
* Tagged format, for easy grepping and expansion.
@@ -229,9 +191,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 >> 10,
+ vmi.used >> 10,
+ vmi.largest_chunk >> 10
);

len += hugetlb_report_meminfo(page + len);
@@ -578,7 +539,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 -uNrp /warthog/kernels/linux-2.6.10-rc1-mm3/fs/proc/task_mmu.c linux-2.6.10-rc1-mm3-frv/fs/proc/task_mmu.c
--- /warthog/kernels/linux-2.6.10-rc1-mm3/fs/proc/task_mmu.c 2004-11-05 13:15:44.000000000 +0000
+++ linux-2.6.10-rc1-mm3-frv/fs/proc/task_mmu.c 2004-11-05 14:13:03.000000000 +0000
@@ -1,8 +1,10 @@
#include <linux/mm.h>
#include <linux/hugetlb.h>
+#include <linux/mount.h>
#include <linux/seq_file.h>
#include <asm/elf.h>
#include <asm/uaccess.h>
+#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->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(&mm->mmap_sem);
+
+ vma = mm->mmap;
+ while (vma) {
+ if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file)
+ break;
+ vma = vma->vm_next;
+ }
+
+ if (vma) {
+ *mnt = mntget(vma->vm_file->f_vfsmnt);
+ *dentry = dget(vma->vm_file->f_dentry);
+ result = 0;
+ }
+
+ up_read(&mm->mmap_sem);
+ mmput(mm);
+out:
+ return result;
+}
+
static int show_map(struct seq_file *m, void *v)
{
struct vm_area_struct *map = v;
diff -uNrp /warthog/kernels/linux-2.6.10-rc1-mm3/fs/proc/task_nommu.c linux-2.6.10-rc1-mm3-frv/fs/proc/task_nommu.c
--- /warthog/kernels/linux-2.6.10-rc1-mm3/fs/proc/task_nommu.c 2004-10-19 10:42:09.000000000 +0100
+++ linux-2.6.10-rc1-mm3-frv/fs/proc/task_nommu.c 2004-11-05 14:13:03.000000000 +0000
@@ -1,7 +1,9 @@

#include <linux/mm.h>
#include <linux/file.h>
+#include <linux/mount.h>
#include <linux/seq_file.h>
+#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(&mm->mmap_sem);
- for (tblock = &mm->context.tblock; tblock; tblock = tblock->next) {
- if (!tblock->rblock)
+ for (tblock = mm->context.tblock; tblock; tblock = tblock->next) {
+ if (!tblock->vma)
continue;
bytes += kobjsize(tblock);
if (atomic_read(&mm->mm_count) > 1 ||
- tblock->rblock->refcount > 1) {
- sbytes += kobjsize(tblock->rblock->kblock);
- sbytes += kobjsize(tblock->rblock);
+ atomic_read(&tblock->vma->vm_usage) > 1) {
+ sbytes += kobjsize((void *) tblock->vma->vm_start);
+ sbytes += kobjsize(tblock->vma);
} else {
- bytes += kobjsize(tblock->rblock->kblock);
- bytes += kobjsize(tblock->rblock);
- slack += kobjsize(tblock->rblock->kblock) -
- tblock->rblock->size;
+ bytes += kobjsize((void *) tblock->vma->vm_start);
+ bytes += kobjsize(tblock->vma);
+ slack += kobjsize((void *) tblock->vma->vm_start) -
+ (tblock->vma->vm_end - tblock->vma->vm_start);
}
}

@@ -69,9 +71,9 @@ unsigned long task_vsize(struct mm_struc
unsigned long vsize = 0;

down_read(&mm->mmap_sem);
- for (tbp = &mm->context.tblock; tbp; tbp = tbp->next) {
- if (tbp->rblock)
- vsize += kobjsize(tbp->rblock->kblock);
+ for (tbp = mm->context.tblock; tbp; tbp = tbp->next) {
+ if (tbp->vma)
+ vsize += kobjsize((void *) tbp->vma->vm_start);
}
up_read(&mm->mmap_sem);
return vsize;
@@ -84,12 +86,11 @@ int task_statm(struct mm_struct *mm, int
int size = kobjsize(mm);

down_read(&mm->mmap_sem);
- 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);
+ for (tbp = mm->context.tblock; tbp; tbp = tbp->next) {
+ size += kobjsize(tbp);
+ if (tbp->vma) {
+ size += kobjsize(tbp->vma);
+ size += kobjsize((void *) tbp->vma->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(&mm->mmap_sem);
+
+ tblock = mm->context.tblock;
+ vma = NULL;
+ while (tblock) {
+ if ((tblock->vma->vm_flags & VM_EXECUTABLE) && tblock->vma->vm_file) {
+ vma = tblock->vma;
+ break;
+ }
+ tblock = tblock->next;
+ }
+
+ if (vma) {
+ *mnt = mntget(vma->vm_file->f_vfsmnt);
+ *dentry = dget(vma->vm_file->f_dentry);
+ result = 0;
+ }
+
+ up_read(&mm->mmap_sem);
+ mmput(mm);
+out:
+ return result;
+}
+
/*
* Albert D. Cahalan suggested to fake entries for the traditional
* sections here. This might be worth investigating.
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/