Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux...
[safe/jmp/linux-2.6] / fs / proc / kcore.c
index 78970e6..6f37c39 100644 (file)
 #include <linux/highmem.h>
 #include <linux/bootmem.h>
 #include <linux/init.h>
+#include <linux/slab.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <linux/list.h>
 #include <linux/ioport.h>
-#include <linux/mm.h>
 #include <linux/memory.h>
 #include <asm/sections.h>
 
@@ -107,6 +107,8 @@ static void free_kclist_ents(struct list_head *head)
  */
 static void __kcore_update_ram(struct list_head *list)
 {
+       int nphdr;
+       size_t size;
        struct kcore_list *tmp, *pos;
        LIST_HEAD(garbage);
 
@@ -121,6 +123,7 @@ static void __kcore_update_ram(struct list_head *list)
        } else
                list_splice(list, &garbage);
        kcore_need_update = 0;
+       proc_root_kcore->size = get_kcore_size(&nphdr, &size);
        write_unlock(&kclist_lock);
 
        free_kclist_ents(&garbage);
@@ -429,7 +432,8 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
        unsigned long start;
 
        read_lock(&kclist_lock);
-       proc_root_kcore->size = size = get_kcore_size(&nphdr, &elf_buflen);
+       size = get_kcore_size(&nphdr, &elf_buflen);
+
        if (buflen == 0 || *fpos >= size) {
                read_unlock(&kclist_lock);
                return 0;
@@ -487,10 +491,10 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
                }
                read_unlock(&kclist_lock);
 
-               if (m == NULL) {
+               if (&m->list == &kclist_head) {
                        if (clear_user(buffer, tsz))
                                return -EFAULT;
-               } else if (is_vmalloc_addr((void *)start)) {
+               } else if (is_vmalloc_or_module_addr((void *)start)) {
                        char * elf_buf;
 
                        elf_buf = kzalloc(tsz, GFP_KERNEL);
@@ -542,6 +546,11 @@ static int open_kcore(struct inode *inode, struct file *filp)
                return -EPERM;
        if (kcore_need_update)
                kcore_update_ram();
+       if (i_size_read(inode) != proc_root_kcore->size) {
+               mutex_lock(&inode->i_mutex);
+               i_size_write(inode, proc_root_kcore->size);
+               mutex_unlock(&inode->i_mutex);
+       }
        return 0;
 }
 
@@ -549,6 +558,7 @@ static int open_kcore(struct inode *inode, struct file *filp)
 static const struct file_operations proc_kcore_operations = {
        .read           = read_kcore,
        .open           = open_kcore,
+       .llseek         = generic_file_llseek,
 };
 
 #ifdef CONFIG_MEMORY_HOTPLUG
@@ -578,7 +588,7 @@ static struct kcore_list kcore_text;
  */
 static void __init proc_kcore_text_init(void)
 {
-       kclist_add(&kcore_text, _stext, _end - _stext, KCORE_TEXT);
+       kclist_add(&kcore_text, _text, _end - _text, KCORE_TEXT);
 }
 #else
 static void __init proc_kcore_text_init(void)
@@ -586,19 +596,39 @@ static void __init proc_kcore_text_init(void)
 }
 #endif
 
+#if defined(CONFIG_MODULES) && defined(MODULES_VADDR)
+/*
+ * MODULES_VADDR has no intersection with VMALLOC_ADDR.
+ */
+struct kcore_list kcore_modules;
+static void __init add_modules_range(void)
+{
+       kclist_add(&kcore_modules, (void *)MODULES_VADDR,
+                       MODULES_END - MODULES_VADDR, KCORE_VMALLOC);
+}
+#else
+static void __init add_modules_range(void)
+{
+}
+#endif
+
 static int __init proc_kcore_init(void)
 {
        proc_root_kcore = proc_create("kcore", S_IRUSR, NULL,
                                      &proc_kcore_operations);
+       if (!proc_root_kcore) {
+               printk(KERN_ERR "couldn't create /proc/kcore\n");
+               return 0; /* Always returns 0. */
+       }
        /* Store text area if it's special */
        proc_kcore_text_init();
        /* Store vmalloc area */
        kclist_add(&kcore_vmalloc, (void *)VMALLOC_START,
                VMALLOC_END - VMALLOC_START, KCORE_VMALLOC);
+       add_modules_range();
        /* Store direct-map area from physical memory map */
        kcore_update_ram();
        hotplug_memory_notifier(kcore_callback, 0);
-       /* Other special area, area-for-module etc is arch specific. */
 
        return 0;
 }