Merge branch 'master' of /usr/src/ntfs-2.6/
[cascardo/linux.git] / fs / proc / proc_misc.c
index 5b6b0b6..826c131 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/time.h>
 #include <linux/kernel.h>
 #include <linux/kernel_stat.h>
+#include <linux/fs.h>
 #include <linux/tty.h>
 #include <linux/string.h>
 #include <linux/mman.h>
@@ -62,7 +63,6 @@
  */
 extern int get_hardware_list(char *);
 extern int get_stram_list(char *);
-extern int get_chrdev_list(char *);
 extern int get_filesystem_list(char *);
 extern int get_exec_domain_list(char *);
 extern int get_dma_list(char *);
@@ -248,6 +248,154 @@ static int cpuinfo_open(struct inode *inode, struct file *file)
 {
        return seq_open(file, &cpuinfo_op);
 }
+
+enum devinfo_states {
+       CHR_HDR,
+       CHR_LIST,
+       BLK_HDR,
+       BLK_LIST,
+       DEVINFO_DONE
+};
+
+struct devinfo_state {
+       void *chrdev;
+       void *blkdev;
+       unsigned int num_records;
+       unsigned int cur_record;
+       enum devinfo_states state;
+};
+
+static void *devinfo_start(struct seq_file *f, loff_t *pos)
+{
+       struct devinfo_state *info = f->private;
+
+       if (*pos) {
+               if ((info) && (*pos <= info->num_records))
+                       return info;
+               return NULL;
+       }
+       info = kmalloc(sizeof(*info), GFP_KERNEL);
+       f->private = info;
+       info->chrdev = acquire_chrdev_list();
+       info->blkdev = acquire_blkdev_list();
+       info->state = CHR_HDR;
+       info->num_records = count_chrdev_list();
+       info->num_records += count_blkdev_list();
+       info->num_records += 2; /* Character and Block headers */
+       *pos = 1;
+       info->cur_record = *pos;
+       return info;
+}
+
+static void *devinfo_next(struct seq_file *f, void *v, loff_t *pos)
+{
+       int idummy;
+       char *ndummy;
+       struct devinfo_state *info = f->private;
+
+       switch (info->state) {
+               case CHR_HDR:
+                       info->state = CHR_LIST;
+                       (*pos)++;
+                       /*fallthrough*/
+               case CHR_LIST:
+                       if (get_chrdev_info(info->chrdev,&idummy,&ndummy)) {
+                               /*
+                                * The character dev list is complete
+                                */
+                               info->state = BLK_HDR;
+                       } else {
+                               info->chrdev = get_next_chrdev(info->chrdev);
+                       }
+                       (*pos)++;
+                       break;
+               case BLK_HDR:
+                       info->state = BLK_LIST;
+                       (*pos)++;
+                       /*fallthrough*/
+               case BLK_LIST:
+                       if (get_blkdev_info(info->blkdev,&idummy,&ndummy)) {
+                               /*
+                                * The block dev list is complete
+                                */
+                               info->state = DEVINFO_DONE;
+                       } else {
+                               info->blkdev = get_next_blkdev(info->blkdev);
+                       }
+                       (*pos)++;
+                       break;
+               case DEVINFO_DONE:
+                       (*pos)++;
+                       info->cur_record = *pos;
+                       info = NULL;
+                       break;
+               default:
+                       break;
+       }
+       if (info)
+               info->cur_record = *pos;
+       return info;
+}
+
+static void devinfo_stop(struct seq_file *f, void *v)
+{
+       struct devinfo_state *info = f->private;
+
+       if (info) {
+               release_chrdev_list(info->chrdev);
+               release_blkdev_list(info->blkdev);
+               f->private = NULL;
+               kfree(info);
+       }
+}
+
+static int devinfo_show(struct seq_file *f, void *arg)
+{
+       int major;
+       char *name;
+       struct devinfo_state *info = f->private;
+
+       switch(info->state) {
+               case CHR_HDR:
+                       seq_printf(f,"Character devices:\n");
+                       /* fallthrough */
+               case CHR_LIST:
+                       if (!get_chrdev_info(info->chrdev,&major,&name))
+                               seq_printf(f,"%3d %s\n",major,name);
+                       break;
+               case BLK_HDR:
+                       seq_printf(f,"\nBlock devices:\n");
+                       /* fallthrough */
+               case BLK_LIST:
+                       if (!get_blkdev_info(info->blkdev,&major,&name))
+                               seq_printf(f,"%3d %s\n",major,name);
+                       break;
+               default:
+                       break;
+       }
+
+       return 0;
+}
+
+static  struct seq_operations devinfo_op = {
+       .start  = devinfo_start,
+       .next   = devinfo_next,
+       .stop   = devinfo_stop,
+       .show   = devinfo_show,
+};
+
+static int devinfo_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &devinfo_op);
+}
+
+static struct file_operations proc_devinfo_operations = {
+       .open           = devinfo_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+
 static struct file_operations proc_cpuinfo_operations = {
        .open           = cpuinfo_open,
        .read           = seq_read,
@@ -323,6 +471,7 @@ static struct file_operations proc_modules_operations = {
 };
 #endif
 
+#ifdef CONFIG_SLAB
 extern struct seq_operations slabinfo_op;
 extern ssize_t slabinfo_write(struct file *, const char __user *, size_t, loff_t *);
 static int slabinfo_open(struct inode *inode, struct file *file)
@@ -336,6 +485,7 @@ static struct file_operations proc_slabinfo_operations = {
        .llseek         = seq_lseek,
        .release        = seq_release,
 };
+#endif
 
 static int show_stat(struct seq_file *p, void *v)
 {
@@ -398,7 +548,7 @@ static int show_stat(struct seq_file *p, void *v)
        }
        seq_printf(p, "intr %llu", (unsigned long long)sum);
 
-#if !defined(CONFIG_PPC64) && !defined(CONFIG_ALPHA)
+#if !defined(CONFIG_PPC64) && !defined(CONFIG_ALPHA) && !defined(CONFIG_IA64)
        for (i = 0; i < NR_IRQS; i++)
                seq_printf(p, " %u", kstat_irqs(i));
 #endif
@@ -448,14 +598,6 @@ static struct file_operations proc_stat_operations = {
        .release        = single_release,
 };
 
-static int devices_read_proc(char *page, char **start, off_t off,
-                                int count, int *eof, void *data)
-{
-       int len = get_chrdev_list(page);
-       len += get_blkdev_list(page+len, len);
-       return proc_calc_metrics(page, start, off, count, eof, len);
-}
-
 /*
  * /proc/interrupts
  */
@@ -580,7 +722,6 @@ void __init proc_misc_init(void)
 #ifdef CONFIG_STRAM_PROC
                {"stram",       stram_read_proc},
 #endif
-               {"devices",     devices_read_proc},
                {"filesystems", filesystems_read_proc},
                {"cmdline",     cmdline_read_proc},
                {"locks",       locks_read_proc},
@@ -596,11 +737,14 @@ void __init proc_misc_init(void)
        entry = create_proc_entry("kmsg", S_IRUSR, &proc_root);
        if (entry)
                entry->proc_fops = &proc_kmsg_operations;
+       create_seq_entry("devices", 0, &proc_devinfo_operations);
        create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations);
        create_seq_entry("partitions", 0, &proc_partitions_operations);
        create_seq_entry("stat", 0, &proc_stat_operations);
        create_seq_entry("interrupts", 0, &proc_interrupts_operations);
+#ifdef CONFIG_SLAB
        create_seq_entry("slabinfo",S_IWUSR|S_IRUGO,&proc_slabinfo_operations);
+#endif
        create_seq_entry("buddyinfo",S_IRUGO, &fragmentation_file_operations);
        create_seq_entry("vmstat",S_IRUGO, &proc_vmstat_file_operations);
        create_seq_entry("zoneinfo",S_IRUGO, &proc_zoneinfo_file_operations);