]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] md: Convert /proc/mdstat to use seq_file
authorNeil Brown <neilb@cse.unsw.edu.au>
Fri, 14 Mar 2003 10:08:21 +0000 (02:08 -0800)
committerLinus Torvalds <torvalds@home.transmeta.com>
Fri, 14 Mar 2003 10:08:21 +0000 (02:08 -0800)
From: Angus Sawyer <angus.sawyer@dsl.pipex.com>

Mainly straightforward convert of sprintf -> seq_printf.  seq_start and
seq_next modelled on /proc/partitions.  locking/ref counting as for
ITERATE_MDDEV.

pos == 0 -> header
pos == n -> nth mddev
pos == 0x10000 -> tail

drivers/md/linear.c
drivers/md/md.c
drivers/md/multipath.c
drivers/md/raid0.c
drivers/md/raid1.c
drivers/md/raid5.c
include/linux/raid/md.h
include/linux/raid/md_k.h

index 1c94ad6ff2a508fdac7c1dee82929abcce692169..380b28ce026bb0174045a56970b352c0f2b58268 100644 (file)
@@ -208,31 +208,29 @@ static int linear_make_request (request_queue_t *q, struct bio *bio)
        return 1;
 }
 
-static int linear_status (char *page, mddev_t *mddev)
+static void linear_status (struct seq_file *seq, mddev_t *mddev)
 {
-       int sz = 0;
 
 #undef MD_DEBUG
 #ifdef MD_DEBUG
        int j;
        linear_conf_t *conf = mddev_to_conf(mddev);
   
-       sz += sprintf(page+sz, "      ");
+       seq_printf(seq, "      ");
        for (j = 0; j < conf->nr_zones; j++)
        {
-               sz += sprintf(page+sz, "[%s",
+               seq_printf(seq, "[%s",
                        bdev_partition_name(conf->hash_table[j].dev0->rdev->bdev));
 
                if (conf->hash_table[j].dev1)
-                       sz += sprintf(page+sz, "/%s] ",
+                       seq_printf(seq, "/%s] ",
                          bdev_partition_name(conf->hash_table[j].dev1->rdev->bdev));
                else
-                       sz += sprintf(page+sz, "] ");
+                       seq_printf(seq, "] ");
        }
-       sz += sprintf(page+sz, "\n");
+       seq_printf(seq, "\n");
 #endif
-       sz += sprintf(page+sz, " %dk rounding", mddev->chunk_size/1024);
-       return sz;
+       seq_printf(seq, " %dk rounding", mddev->chunk_size/1024);
 }
 
 
index 03ee64e3d746505b212fe265e1c74cd9c3e7e9a1..f57b98e067cc8ac0bcaaa9ab421d4e203b1f3bc8 100644 (file)
@@ -2621,30 +2621,30 @@ void md_error(mddev_t *mddev, mdk_rdev_t *rdev)
        md_recover_arrays();
 }
 
-static int status_unused(char * page)
+/* seq_file implementation /proc/mdstat */
+
+static void status_unused(struct seq_file *seq)
 {
-       int sz = 0, i = 0;
+       int i = 0;
        mdk_rdev_t *rdev;
        struct list_head *tmp;
 
-       sz += sprintf(page + sz, "unused devices: ");
+       seq_printf(seq, "unused devices: ");
 
        ITERATE_RDEV_PENDING(rdev,tmp) {
                i++;
-               sz += sprintf(page + sz, "%s ",
+               seq_printf(seq, "%s ",
                              bdev_partition_name(rdev->bdev));
        }
        if (!i)
-               sz += sprintf(page + sz, "<none>");
+               seq_printf(seq, "<none>");
 
-       sz += sprintf(page + sz, "\n");
-       return sz;
+       seq_printf(seq, "\n");
 }
 
 
-static int status_resync(char * page, mddev_t * mddev)
+static void status_resync(struct seq_file *seq, mddev_t * mddev)
 {
-       int sz = 0;
        unsigned long max_blocks, resync, res, dt, db, rt;
 
        resync = (mddev->curr_resync - atomic_read(&mddev->recovery_active))/2;
@@ -2655,20 +2655,20 @@ static int status_resync(char * page, mddev_t * mddev)
         */
        if (!max_blocks) {
                MD_BUG();
-               return 0;
+               return;
        }
        res = (resync/1024)*1000/(max_blocks/1024 + 1);
        {
                int i, x = res/50, y = 20-x;
-               sz += sprintf(page + sz, "[");
+               seq_printf(seq, "[");
                for (i = 0; i < x; i++)
-                       sz += sprintf(page + sz, "=");
-               sz += sprintf(page + sz, ">");
+                       seq_printf(seq, "=");
+               seq_printf(seq, ">");
                for (i = 0; i < y; i++)
-                       sz += sprintf(page + sz, ".");
-               sz += sprintf(page + sz, "] ");
+                       seq_printf(seq, ".");
+               seq_printf(seq, "] ");
        }
-       sz += sprintf(page + sz, " %s =%3lu.%lu%% (%lu/%lu)",
+       seq_printf(seq, " %s =%3lu.%lu%% (%lu/%lu)",
                      (mddev->spares ? "recovery" : "resync"),
                      res/10, res % 10, resync, max_blocks);
 
@@ -2686,44 +2686,110 @@ static int status_resync(char * page, mddev_t * mddev)
        db = resync - (mddev->resync_mark_cnt/2);
        rt = (dt * ((max_blocks-resync) / (db/100+1)))/100;
 
-       sz += sprintf(page + sz, " finish=%lu.%lumin", rt / 60, (rt % 60)/6);
+       seq_printf(seq, " finish=%lu.%lumin", rt / 60, (rt % 60)/6);
+
+       seq_printf(seq, " speed=%ldK/sec", db/dt);
+}
+
+static void *md_seq_start(struct seq_file *seq, loff_t *pos)
+{
+       struct list_head *tmp;
+       loff_t l = *pos;
+       mddev_t *mddev;
+
+       if (l > 0x10000)
+               return NULL;
+       if (!l--)
+               /* header */
+               return (void*)1;
+
+       spin_lock(&all_mddevs_lock);
+       list_for_each(tmp,&all_mddevs)
+               if (!l--) {
+                       mddev = list_entry(tmp, mddev_t, all_mddevs);
+                       mddev_get(mddev);
+                       spin_unlock(&all_mddevs_lock);
+                       return mddev;
+               }
+       spin_unlock(&all_mddevs_lock);
+       return (void*)2;/* tail */
+}
+
+static void *md_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+       struct list_head *tmp;
+       mddev_t *next_mddev, *mddev = v;
+       
+       ++*pos;
+       if (v == (void*)2)
+               return NULL;
+
+       spin_lock(&all_mddevs_lock);
+       if (v == (void*)1)
+               tmp = all_mddevs.next;
+       else
+               tmp = mddev->all_mddevs.next;
+       if (tmp != &all_mddevs)
+               next_mddev = mddev_get(list_entry(tmp,mddev_t,all_mddevs));
+       else {
+               next_mddev = (void*)2;
+               *pos = 0x10000;
+       }               
+       spin_unlock(&all_mddevs_lock);
+
+       if (v != (void*)1)
+               mddev_put(mddev);
+       return next_mddev;
+
+}
 
-       sz += sprintf(page + sz, " speed=%ldK/sec", db/dt);
+static void md_seq_stop(struct seq_file *seq, void *v)
+{
+       mddev_t *mddev = v;
 
-       return sz;
+       if (mddev && v != (void*)1 && v != (void*)2)
+               mddev_put(mddev);
 }
 
-static int md_status_read_proc(char *page, char **start, off_t off,
-                       int count, int *eof, void *data)
+static int md_seq_show(struct seq_file *seq, void *v)
 {
-       int sz = 0, j;
+       mddev_t *mddev = v;
        sector_t size;
-       struct list_head *tmp, *tmp2;
+       struct list_head *tmp2;
        mdk_rdev_t *rdev;
-       mddev_t *mddev;
+       int i;
 
-       sz += sprintf(page + sz, "Personalities : ");
-       for (j = 0; j < MAX_PERSONALITY; j++)
-       if (pers[j])
-               sz += sprintf(page+sz, "[%s] ", pers[j]->name);
+       if (v == (void*)1) {
+               seq_printf(seq, "Personalities : ");
+               for (i = 0; i < MAX_PERSONALITY; i++)
+                       if (pers[i])
+                               seq_printf(seq, "[%s] ", pers[i]->name);
 
-       sz += sprintf(page+sz, "\n");
+               seq_printf(seq, "\n");
+               return 0;
+       }
+       if (v == (void*)2) {
+               status_unused(seq);
+               return 0;
+       }
 
-       ITERATE_MDDEV(mddev,tmp) if (mddev_lock(mddev)==0) {
-               sz += sprintf(page + sz, "md%d : %sactive", mdidx(mddev),
+       if (mddev_lock(mddev)!=0) 
+               return -EINTR;
+       if (mddev->pers || mddev->raid_disks || !list_empty(&mddev->disks)) {
+               seq_printf(seq, "md%d : %sactive", mdidx(mddev),
                                                mddev->pers ? "" : "in");
                if (mddev->pers) {
                        if (mddev->ro)
-                               sz += sprintf(page + sz, " (read-only)");
-                       sz += sprintf(page + sz, " %s", mddev->pers->name);
+                               seq_printf(seq, " (read-only)");
+                       seq_printf(seq, " %s", mddev->pers->name);
                }
 
                size = 0;
                ITERATE_RDEV(mddev,rdev,tmp2) {
-                       sz += sprintf(page + sz, " %s[%d]",
+                       seq_printf(seq, " %s[%d]",
                                bdev_partition_name(rdev->bdev), rdev->desc_nr);
                        if (rdev->faulty) {
-                               sz += sprintf(page + sz, "(F)");
+                               seq_printf(seq, "(F)");
                                continue;
                        }
                        size += rdev->size;
@@ -2731,34 +2797,50 @@ static int md_status_read_proc(char *page, char **start, off_t off,
 
                if (!list_empty(&mddev->disks)) {
                        if (mddev->pers)
-                               sz += sprintf(page + sz, "\n      %llu blocks",
+                               seq_printf(seq, "\n      %llu blocks",
                                                 (unsigned long long)md_size[mdidx(mddev)]);
                        else
-                               sz += sprintf(page + sz, "\n      %llu blocks", (unsigned long long)size);
+                               seq_printf(seq, "\n      %llu blocks", (unsigned long long)size);
                }
 
-               if (!mddev->pers) {
-                       sz += sprintf(page+sz, "\n");
-                       mddev_unlock(mddev);
-                       continue;
+               if (mddev->pers) {
+                       mddev->pers->status (seq, mddev);
+                       seq_printf(seq, "\n      ");
+                       if (mddev->curr_resync > 2)
+                               status_resync (seq, mddev);
+                       else if (mddev->curr_resync == 1 || mddev->curr_resync == 2)
+                               seq_printf(seq, "       resync=DELAYED");
                }
 
-               sz += mddev->pers->status (page+sz, mddev);
+               seq_printf(seq, "\n");
+       }
+       mddev_unlock(mddev);
+       
+       return 0;
+}
 
-               sz += sprintf(page+sz, "\n      ");
-               if (mddev->curr_resync > 2)
-                       sz += status_resync (page+sz, mddev);
-               else if (mddev->curr_resync == 1 || mddev->curr_resync == 2)
-                               sz += sprintf(page + sz, "      resync=DELAYED");
+static struct seq_operations md_seq_ops = {
+       .start  = md_seq_start,
+       .next   = md_seq_next,
+       .stop   = md_seq_stop,
+       .show   = md_seq_show,
+};
 
-               sz += sprintf(page + sz, "\n");
-               mddev_unlock(mddev);
-       }
-       sz += status_unused(page + sz);
+static int md_seq_open(struct inode *inode, struct file *file)
+{
+       int error;
 
-       return sz;
+       error = seq_open(file, &md_seq_ops);
+       return error;
 }
 
+static struct file_operations md_seq_fops = {
+       .open           = md_seq_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+
 int register_md_personality(int pnum, mdk_personality_t *p)
 {
        if (pnum >= MAX_PERSONALITY) {
@@ -3196,6 +3278,7 @@ struct notifier_block md_notifier = {
 
 static void md_geninit(void)
 {
+       struct proc_dir_entry *p;
        int i;
 
        for(i = 0; i < MAX_MD_DEVS; i++) {
@@ -3205,7 +3288,9 @@ static void md_geninit(void)
        dprintk("md: sizeof(mdp_super_t) = %d\n", (int)sizeof(mdp_super_t));
 
 #ifdef CONFIG_PROC_FS
-       create_proc_read_entry("mdstat", 0, NULL, md_status_read_proc, NULL);
+       p = create_proc_entry("mdstat", S_IRUGO, NULL);
+       if (p)
+               p->proc_fops = &md_seq_fops;
 #endif
 }
 
index 5b96e4a42d2154e95465ac0a8f742359f0f1272d..1eaa36356155451da290c7e1e8c4fdd44e65a80f 100644 (file)
@@ -185,19 +185,18 @@ static int multipath_make_request (request_queue_t *q, struct bio * bio)
        return 0;
 }
 
-static int multipath_status (char *page, mddev_t *mddev)
+static void multipath_status (struct seq_file *seq, mddev_t *mddev)
 {
        multipath_conf_t *conf = mddev_to_conf(mddev);
-       int sz = 0, i;
+       int i;
        
-       sz += sprintf (page+sz, " [%d/%d] [", conf->raid_disks,
+       seq_printf (seq, " [%d/%d] [", conf->raid_disks,
                                                 conf->working_disks);
        for (i = 0; i < conf->raid_disks; i++)
-               sz += sprintf (page+sz, "%s",
+               seq_printf (seq, "%s",
                               conf->multipaths[i].rdev && 
                               conf->multipaths[i].rdev->in_sync ? "U" : "_");
-       sz += sprintf (page+sz, "]");
-       return sz;
+       seq_printf (seq, "]");
 }
 
 #define LAST_DISK KERN_ALERT \
index 0d83f3647f937d8822dc1afedb8a806488df56b7..00a79d9b364bd5d27ba638c3faf148a8b9a0b3f1 100644 (file)
@@ -372,41 +372,40 @@ bad_zone1:
        return 0;
 }
                           
-static int raid0_status (char *page, mddev_t *mddev)
+static void raid0_status (struct seq_file *seq, mddev_t *mddev)
 {
-       int sz = 0;
 #undef MD_DEBUG
 #ifdef MD_DEBUG
        int j, k;
        raid0_conf_t *conf = mddev_to_conf(mddev);
   
-       sz += sprintf(page + sz, "      ");
+       seq_printf(seq, "      ");
        for (j = 0; j < conf->nr_zones; j++) {
-               sz += sprintf(page + sz, "[z%d",
+               seq_printf(seq, "[z%d",
                                conf->hash_table[j].zone0 - conf->strip_zone);
                if (conf->hash_table[j].zone1)
-                       sz += sprintf(page+sz, "/z%d] ",
+                       seq_printf(seq, "/z%d] ",
                                conf->hash_table[j].zone1 - conf->strip_zone);
                else
-                       sz += sprintf(page+sz, "] ");
+                       seq_printf(seq, "] ");
        }
   
-       sz += sprintf(page + sz, "\n");
+       seq_printf(seq, "\n");
   
        for (j = 0; j < conf->nr_strip_zones; j++) {
-               sz += sprintf(page + sz, "      z%d=[", j);
+               seq_printf(seq, "      z%d=[", j);
                for (k = 0; k < conf->strip_zone[j].nb_dev; k++)
-                       sz += sprintf (page+sz, "%s/", bdev_partition_name(
+                       seq_printf (seq, "%s/", bdev_partition_name(
                                conf->strip_zone[j].dev[k]->bdev));
-               sz--;
-               sz += sprintf (page+sz, "] zo=%d do=%d s=%d\n",
+
+               seq_printf (seq, "] zo=%d do=%d s=%d\n",
                                conf->strip_zone[j].zone_offset,
                                conf->strip_zone[j].dev_offset,
                                conf->strip_zone[j].size);
        }
 #endif
-       sz += sprintf(page + sz, " %dk chunks", mddev->chunk_size/1024);
-       return sz;
+       seq_printf(seq, " %dk chunks", mddev->chunk_size/1024);
+       return;
 }
 
 static mdk_personality_t raid0_personality=
index 83ee73ef172fe6da25cddd8576ef86d1a29d9925..152656ef5012eda01dd7706e4b78e254a55bb963 100644 (file)
@@ -571,19 +571,18 @@ static int make_request(request_queue_t *q, struct bio * bio)
        return 0;
 }
 
-static int status(char *page, mddev_t *mddev)
+static void status(struct seq_file *seq, mddev_t *mddev)
 {
        conf_t *conf = mddev_to_conf(mddev);
-       int sz = 0, i;
+       int i;
 
-       sz += sprintf(page+sz, " [%d/%d] [", conf->raid_disks,
+       seq_printf(seq, " [%d/%d] [", conf->raid_disks,
                                                conf->working_disks);
        for (i = 0; i < conf->raid_disks; i++)
-               sz += sprintf(page+sz, "%s",
+               seq_printf(seq, "%s",
                              conf->mirrors[i].rdev &&
                              conf->mirrors[i].rdev->in_sync ? "U" : "_");
-       sz += sprintf (page+sz, "]");
-       return sz;
+       seq_printf(seq, "]");
 }
 
 #define LAST_DISK KERN_ALERT \
index 7949de5f8e875f7f99ec13b3ea1db6aadcf671c0..abec935d78d12475dc09fd5b35929b8e26325f2b 100644 (file)
@@ -1579,24 +1579,23 @@ static void printall (raid5_conf_t *conf)
 }
 #endif
 
-static int status (char *page, mddev_t *mddev)
+static void status (struct seq_file *seq, mddev_t *mddev)
 {
        raid5_conf_t *conf = (raid5_conf_t *) mddev->private;
-       int sz = 0, i;
+       int i;
 
-       sz += sprintf (page+sz, " level %d, %dk chunk, algorithm %d", mddev->level, mddev->chunk_size >> 10, mddev->layout);
-       sz += sprintf (page+sz, " [%d/%d] [", conf->raid_disks, conf->working_disks);
+       seq_printf (seq, " level %d, %dk chunk, algorithm %d", mddev->level, mddev->chunk_size >> 10, mddev->layout);
+       seq_printf (seq, " [%d/%d] [", conf->raid_disks, conf->working_disks);
        for (i = 0; i < conf->raid_disks; i++)
-               sz += sprintf (page+sz, "%s",
+               seq_printf (seq, "%s",
                               conf->disks[i].rdev &&
                               conf->disks[i].rdev->in_sync ? "U" : "_");
-       sz += sprintf (page+sz, "]");
+       seq_printf (seq, "]");
 #if RAID5_DEBUG
 #define D(x) \
-       sz += sprintf (page+sz, "<"#x":%d>", atomic_read(&conf->x))
+       seq_printf (seq, "<"#x":%d>", atomic_read(&conf->x))
        printall(conf);
 #endif
-       return sz;
 }
 
 static void print_raid5_conf (raid5_conf_t *conf)
index d7834b08cc88df0bd8be027a55f13fa7a2c56c7c..3260343d634ec3f7d77020a8aa6cb4b558b6ecaf 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/module.h>
 #include <linux/hdreg.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/smp_lock.h>
 #include <linux/delay.h>
 #include <net/checksum.h>
index 6426a2c3fe8f1ab7e41adf3754fddffce30fa4a0..cf7505f655dabf79c901d072b63e444e61e97b34 100644 (file)
@@ -245,7 +245,7 @@ struct mdk_personality_s
        int (*make_request)(request_queue_t *q, struct bio *bio);
        int (*run)(mddev_t *mddev);
        int (*stop)(mddev_t *mddev);
-       int (*status)(char *page, mddev_t *mddev);
+       void (*status)(struct seq_file *seq, mddev_t *mddev);
        /* error_handler must set ->faulty and clear ->in_sync
         * if appropriate, and should abort recovery if needed 
         */