Commit d7710d00 authored by Neil Brown's avatar Neil Brown Committed by Linus Torvalds

[PATCH] md: Convert /proc/mdstat to use seq_file

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
parent 8cdeea1a
...@@ -208,31 +208,29 @@ static int linear_make_request (request_queue_t *q, struct bio *bio) ...@@ -208,31 +208,29 @@ static int linear_make_request (request_queue_t *q, struct bio *bio)
return 1; 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 #undef MD_DEBUG
#ifdef MD_DEBUG #ifdef MD_DEBUG
int j; int j;
linear_conf_t *conf = mddev_to_conf(mddev); linear_conf_t *conf = mddev_to_conf(mddev);
sz += sprintf(page+sz, " "); seq_printf(seq, " ");
for (j = 0; j < conf->nr_zones; j++) 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)); bdev_partition_name(conf->hash_table[j].dev0->rdev->bdev));
if (conf->hash_table[j].dev1) 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)); bdev_partition_name(conf->hash_table[j].dev1->rdev->bdev));
else else
sz += sprintf(page+sz, "] "); seq_printf(seq, "] ");
} }
sz += sprintf(page+sz, "\n"); seq_printf(seq, "\n");
#endif #endif
sz += sprintf(page+sz, " %dk rounding", mddev->chunk_size/1024); seq_printf(seq, " %dk rounding", mddev->chunk_size/1024);
return sz;
} }
......
...@@ -2621,30 +2621,30 @@ void md_error(mddev_t *mddev, mdk_rdev_t *rdev) ...@@ -2621,30 +2621,30 @@ void md_error(mddev_t *mddev, mdk_rdev_t *rdev)
md_recover_arrays(); 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; mdk_rdev_t *rdev;
struct list_head *tmp; struct list_head *tmp;
sz += sprintf(page + sz, "unused devices: "); seq_printf(seq, "unused devices: ");
ITERATE_RDEV_PENDING(rdev,tmp) { ITERATE_RDEV_PENDING(rdev,tmp) {
i++; i++;
sz += sprintf(page + sz, "%s ", seq_printf(seq, "%s ",
bdev_partition_name(rdev->bdev)); bdev_partition_name(rdev->bdev));
} }
if (!i) if (!i)
sz += sprintf(page + sz, "<none>"); seq_printf(seq, "<none>");
sz += sprintf(page + sz, "\n"); seq_printf(seq, "\n");
return sz;
} }
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; unsigned long max_blocks, resync, res, dt, db, rt;
resync = (mddev->curr_resync - atomic_read(&mddev->recovery_active))/2; resync = (mddev->curr_resync - atomic_read(&mddev->recovery_active))/2;
...@@ -2655,20 +2655,20 @@ static int status_resync(char * page, mddev_t * mddev) ...@@ -2655,20 +2655,20 @@ static int status_resync(char * page, mddev_t * mddev)
*/ */
if (!max_blocks) { if (!max_blocks) {
MD_BUG(); MD_BUG();
return 0; return;
} }
res = (resync/1024)*1000/(max_blocks/1024 + 1); res = (resync/1024)*1000/(max_blocks/1024 + 1);
{ {
int i, x = res/50, y = 20-x; int i, x = res/50, y = 20-x;
sz += sprintf(page + sz, "["); seq_printf(seq, "[");
for (i = 0; i < x; i++) for (i = 0; i < x; i++)
sz += sprintf(page + sz, "="); seq_printf(seq, "=");
sz += sprintf(page + sz, ">"); seq_printf(seq, ">");
for (i = 0; i < y; i++) for (i = 0; i < y; i++)
sz += sprintf(page + sz, "."); seq_printf(seq, ".");
sz += sprintf(page + sz, "] "); seq_printf(seq, "] ");
} }
sz += sprintf(page + sz, " %s =%3lu.%lu%% (%lu/%lu)", seq_printf(seq, " %s =%3lu.%lu%% (%lu/%lu)",
(mddev->spares ? "recovery" : "resync"), (mddev->spares ? "recovery" : "resync"),
res/10, res % 10, resync, max_blocks); res/10, res % 10, resync, max_blocks);
...@@ -2686,44 +2686,110 @@ static int status_resync(char * page, mddev_t * mddev) ...@@ -2686,44 +2686,110 @@ static int status_resync(char * page, mddev_t * mddev)
db = resync - (mddev->resync_mark_cnt/2); db = resync - (mddev->resync_mark_cnt/2);
rt = (dt * ((max_blocks-resync) / (db/100+1)))/100; 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, static int md_seq_show(struct seq_file *seq, void *v)
int count, int *eof, void *data)
{ {
int sz = 0, j; mddev_t *mddev = v;
sector_t size; sector_t size;
struct list_head *tmp, *tmp2; struct list_head *tmp2;
mdk_rdev_t *rdev; mdk_rdev_t *rdev;
mddev_t *mddev; int i;
sz += sprintf(page + sz, "Personalities : "); if (v == (void*)1) {
for (j = 0; j < MAX_PERSONALITY; j++) seq_printf(seq, "Personalities : ");
if (pers[j]) for (i = 0; i < MAX_PERSONALITY; i++)
sz += sprintf(page+sz, "[%s] ", pers[j]->name); 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) { if (mddev_lock(mddev)!=0)
sz += sprintf(page + sz, "md%d : %sactive", mdidx(mddev), return -EINTR;
if (mddev->pers || mddev->raid_disks || !list_empty(&mddev->disks)) {
seq_printf(seq, "md%d : %sactive", mdidx(mddev),
mddev->pers ? "" : "in"); mddev->pers ? "" : "in");
if (mddev->pers) { if (mddev->pers) {
if (mddev->ro) if (mddev->ro)
sz += sprintf(page + sz, " (read-only)"); seq_printf(seq, " (read-only)");
sz += sprintf(page + sz, " %s", mddev->pers->name); seq_printf(seq, " %s", mddev->pers->name);
} }
size = 0; size = 0;
ITERATE_RDEV(mddev,rdev,tmp2) { ITERATE_RDEV(mddev,rdev,tmp2) {
sz += sprintf(page + sz, " %s[%d]", seq_printf(seq, " %s[%d]",
bdev_partition_name(rdev->bdev), rdev->desc_nr); bdev_partition_name(rdev->bdev), rdev->desc_nr);
if (rdev->faulty) { if (rdev->faulty) {
sz += sprintf(page + sz, "(F)"); seq_printf(seq, "(F)");
continue; continue;
} }
size += rdev->size; size += rdev->size;
...@@ -2731,34 +2797,50 @@ static int md_status_read_proc(char *page, char **start, off_t off, ...@@ -2731,34 +2797,50 @@ static int md_status_read_proc(char *page, char **start, off_t off,
if (!list_empty(&mddev->disks)) { if (!list_empty(&mddev->disks)) {
if (mddev->pers) if (mddev->pers)
sz += sprintf(page + sz, "\n %llu blocks", seq_printf(seq, "\n %llu blocks",
(unsigned long long)md_size[mdidx(mddev)]); (unsigned long long)md_size[mdidx(mddev)]);
else 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) { if (mddev->pers) {
sz += sprintf(page+sz, "\n"); mddev->pers->status (seq, mddev);
mddev_unlock(mddev); seq_printf(seq, "\n ");
continue; 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 "); static struct seq_operations md_seq_ops = {
if (mddev->curr_resync > 2) .start = md_seq_start,
sz += status_resync (page+sz, mddev); .next = md_seq_next,
else if (mddev->curr_resync == 1 || mddev->curr_resync == 2) .stop = md_seq_stop,
sz += sprintf(page + sz, " resync=DELAYED"); .show = md_seq_show,
};
sz += sprintf(page + sz, "\n"); static int md_seq_open(struct inode *inode, struct file *file)
mddev_unlock(mddev); {
} int error;
sz += status_unused(page + sz);
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) int register_md_personality(int pnum, mdk_personality_t *p)
{ {
if (pnum >= MAX_PERSONALITY) { if (pnum >= MAX_PERSONALITY) {
...@@ -3196,6 +3278,7 @@ struct notifier_block md_notifier = { ...@@ -3196,6 +3278,7 @@ struct notifier_block md_notifier = {
static void md_geninit(void) static void md_geninit(void)
{ {
struct proc_dir_entry *p;
int i; int i;
for(i = 0; i < MAX_MD_DEVS; i++) { for(i = 0; i < MAX_MD_DEVS; i++) {
...@@ -3205,7 +3288,9 @@ static void md_geninit(void) ...@@ -3205,7 +3288,9 @@ static void md_geninit(void)
dprintk("md: sizeof(mdp_super_t) = %d\n", (int)sizeof(mdp_super_t)); dprintk("md: sizeof(mdp_super_t) = %d\n", (int)sizeof(mdp_super_t));
#ifdef CONFIG_PROC_FS #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 #endif
} }
......
...@@ -185,19 +185,18 @@ static int multipath_make_request (request_queue_t *q, struct bio * bio) ...@@ -185,19 +185,18 @@ static int multipath_make_request (request_queue_t *q, struct bio * bio)
return 0; 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); 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); conf->working_disks);
for (i = 0; i < conf->raid_disks; i++) 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 &&
conf->multipaths[i].rdev->in_sync ? "U" : "_"); conf->multipaths[i].rdev->in_sync ? "U" : "_");
sz += sprintf (page+sz, "]"); seq_printf (seq, "]");
return sz;
} }
#define LAST_DISK KERN_ALERT \ #define LAST_DISK KERN_ALERT \
......
...@@ -372,41 +372,40 @@ static int raid0_make_request (request_queue_t *q, struct bio *bio) ...@@ -372,41 +372,40 @@ static int raid0_make_request (request_queue_t *q, struct bio *bio)
return 0; 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 #undef MD_DEBUG
#ifdef MD_DEBUG #ifdef MD_DEBUG
int j, k; int j, k;
raid0_conf_t *conf = mddev_to_conf(mddev); raid0_conf_t *conf = mddev_to_conf(mddev);
sz += sprintf(page + sz, " "); seq_printf(seq, " ");
for (j = 0; j < conf->nr_zones; j++) { 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); conf->hash_table[j].zone0 - conf->strip_zone);
if (conf->hash_table[j].zone1) 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); conf->hash_table[j].zone1 - conf->strip_zone);
else 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++) { 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++) 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)); 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].zone_offset,
conf->strip_zone[j].dev_offset, conf->strip_zone[j].dev_offset,
conf->strip_zone[j].size); conf->strip_zone[j].size);
} }
#endif #endif
sz += sprintf(page + sz, " %dk chunks", mddev->chunk_size/1024); seq_printf(seq, " %dk chunks", mddev->chunk_size/1024);
return sz; return;
} }
static mdk_personality_t raid0_personality= static mdk_personality_t raid0_personality=
......
...@@ -571,19 +571,18 @@ static int make_request(request_queue_t *q, struct bio * bio) ...@@ -571,19 +571,18 @@ static int make_request(request_queue_t *q, struct bio * bio)
return 0; 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); 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); conf->working_disks);
for (i = 0; i < conf->raid_disks; i++) 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 &&
conf->mirrors[i].rdev->in_sync ? "U" : "_"); conf->mirrors[i].rdev->in_sync ? "U" : "_");
sz += sprintf (page+sz, "]"); seq_printf(seq, "]");
return sz;
} }
#define LAST_DISK KERN_ALERT \ #define LAST_DISK KERN_ALERT \
......
...@@ -1579,24 +1579,23 @@ static void printall (raid5_conf_t *conf) ...@@ -1579,24 +1579,23 @@ static void printall (raid5_conf_t *conf)
} }
#endif #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; 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); seq_printf (seq, " 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, " [%d/%d] [", conf->raid_disks, conf->working_disks);
for (i = 0; i < conf->raid_disks; i++) 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 &&
conf->disks[i].rdev->in_sync ? "U" : "_"); conf->disks[i].rdev->in_sync ? "U" : "_");
sz += sprintf (page+sz, "]"); seq_printf (seq, "]");
#if RAID5_DEBUG #if RAID5_DEBUG
#define D(x) \ #define D(x) \
sz += sprintf (page+sz, "<"#x":%d>", atomic_read(&conf->x)) seq_printf (seq, "<"#x":%d>", atomic_read(&conf->x))
printall(conf); printall(conf);
#endif #endif
return sz;
} }
static void print_raid5_conf (raid5_conf_t *conf) static void print_raid5_conf (raid5_conf_t *conf)
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/hdreg.h> #include <linux/hdreg.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <net/checksum.h> #include <net/checksum.h>
......
...@@ -245,7 +245,7 @@ struct mdk_personality_s ...@@ -245,7 +245,7 @@ struct mdk_personality_s
int (*make_request)(request_queue_t *q, struct bio *bio); int (*make_request)(request_queue_t *q, struct bio *bio);
int (*run)(mddev_t *mddev); int (*run)(mddev_t *mddev);
int (*stop)(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 /* error_handler must set ->faulty and clear ->in_sync
* if appropriate, and should abort recovery if needed * if appropriate, and should abort recovery if needed
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment