Re: iostats broken for devices with major number > DK_MAX_DISK (16)

From: James Stevenson (james@stev.org)
Date: Tue Nov 12 2002 - 18:40:43 EST


> > > sorry for the intrusion. I noticed iostats didn't display statistics for
> > > devices on Mylex RAID constrollers. Det statistics are completely
> > > missing in /proc/stat. The reason seems to be an assumption that disks
> > > Devices on Mylex-controllers have major number 48. Would it break
> > > anything if DK_MAX_MAJOR if set higher (e.g. 64)?
> > >
> > > AFAIK this goes for both 2.4 and the 2.5 series.
> >
> > i have been runing with 2.4.x kernel with this number
> > set higher i have still yet to see any problem with it
> > other than using more memory.
> >
> We've had the same problem, and we've been running with DK_MAX_MAJOR == 64,
> using megaraid and acceleraid 2000 controllers.
> Haven't seen any problems
> cliffw
> OSDL

i had a patch for a while which solved the problem
though it had problems with scsi stuff and i dont know
if it will even run at all last time i was running it
was on 2.4.17 i think lots of stuff changed and i did not port
it to 2.4.19. Its was not my patch though i picked it off this list
and yet again i cannot remember the original author.

heres what it is but dont hold me to this its not tested on newer
kernels !!.

        James

Index: drivers/block/ll_rw_blk.c
===================================================================
RCS file: /cvs-root/kernel-source/drivers/block/ll_rw_blk.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 ll_rw_blk.c
--- drivers/block/ll_rw_blk.c 30 Dec 2001 08:47:06 -0000 1.1.1.1
+++ drivers/block/ll_rw_blk.c 13 Jan 2002 15:33:30 -0000
@@ -183,7 +183,11 @@
 
         if (count)
                 printk("blk_cleanup_queue: leaked requests (%d)\n", count);
-
+ /*
+ * free statistics structure
+ */
+ kfree(q->dk_stat);
+
         memset(q, 0, sizeof(*q));
 }
 
@@ -393,6 +397,8 @@
  **/
 void blk_init_queue(request_queue_t * q, request_fn_proc * rfn)
 {
+ struct disk_stat * new;
+
         INIT_LIST_HEAD(&q->queue_head);
         elevator_init(&q->elevator, ELEVATOR_LINUS);
         blk_init_free_list(q);
@@ -413,6 +419,15 @@
          */
         q->plug_device_fn = generic_plug_device;
         q->head_active = 1;
+ /*
+ * At last, allocate and initialize the statistics
+ */
+ new = kmalloc(sizeof(struct disk_stat), GFP_KERNEL);
+ if (new == NULL)
+ printk(KERN_ERR "blk_init_queue:error allocating statisitcs\n");
+ else
+ memset(new, 0, sizeof(struct disk_stat));
+ q->dk_stat = new;
 }
 
 #define blkdev_free_rq(list) list_entry((list)->next, struct request, queue);
@@ -497,23 +512,18 @@
         else ro_bits[major][minor >> 5] &= ~(1 << (minor & 31));
 }
 
-inline void drive_stat_acct (kdev_t dev, int rw,
+inline void drive_stat_acct (struct disk_stat * ds, int rw,
                                 unsigned long nr_sectors, int new_io)
 {
- unsigned int major = MAJOR(dev);
- unsigned int index;
-
- index = disk_index(dev);
- if ((index >= DK_MAX_DISK) || (major >= DK_MAX_MAJOR))
+ if (ds == NULL)
                 return;
 
- kstat.dk_drive[major][index] += new_io;
         if (rw == READ) {
- kstat.dk_drive_rio[major][index] += new_io;
- kstat.dk_drive_rblk[major][index] += nr_sectors;
+ ds->dk_drive_rio += new_io;
+ ds->dk_drive_rblk += nr_sectors;
         } else if (rw == WRITE) {
- kstat.dk_drive_wio[major][index] += new_io;
- kstat.dk_drive_wblk[major][index] += nr_sectors;
+ ds->dk_drive_wio += new_io;
+ ds->dk_drive_wblk += nr_sectors;
         } else
                 printk(KERN_ERR "drive_stat_acct: cmd not R/W?\n");
 }
@@ -529,7 +539,7 @@
 static inline void add_request(request_queue_t * q, struct request * req,
                                struct list_head *insert_here)
 {
- drive_stat_acct(req->rq_dev, req->cmd, req->nr_sectors, 1);
+ drive_stat_acct(q->dk_stat, req->cmd, req->nr_sectors, 1);
 
         if (!q->plugged && q->head_active && insert_here == &q->queue_head) {
                 spin_unlock_irq(&io_request_lock);
@@ -701,7 +711,7 @@
                         req->bhtail = bh;
                         req->nr_sectors = req->hard_nr_sectors += count;
                         blk_started_io(count);
- drive_stat_acct(req->rq_dev, req->cmd, count, 0);
+ drive_stat_acct(q->dk_stat, req->cmd, count, 0);
                         attempt_back_merge(q, req, max_sectors, max_segments);
                         goto out;
 
@@ -716,7 +726,7 @@
                         req->sector = req->hard_sector = sector;
                         req->nr_sectors = req->hard_nr_sectors += count;
                         blk_started_io(count);
- drive_stat_acct(req->rq_dev, req->cmd, count, 0);
+ drive_stat_acct(q->dk_stat, req->cmd, count, 0);
                         attempt_front_merge(q, head, req, max_sectors, max_segments);
                         goto out;
 
Index: drivers/ide/ide.c
===================================================================
RCS file: /cvs-root/kernel-source/drivers/ide/ide.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 ide.c
--- drivers/ide/ide.c 30 Dec 2001 08:47:37 -0000 1.1.1.1
+++ drivers/ide/ide.c 13 Jan 2002 15:33:31 -0000
@@ -1451,8 +1451,10 @@
 request_queue_t *ide_get_queue (kdev_t dev)
 {
         ide_hwif_t *hwif = (ide_hwif_t *)blk_dev[MAJOR(dev)].data;
-
- return &hwif->drives[DEVICE_NR(dev) & 1].queue;
+ if (DEVICE_NR(dev) >= MAX_DRIVES)
+ return NULL;
+ else
+ return &hwif->drives[DEVICE_NR(dev)].queue;
 }
 
 /*
Index: drivers/md/md.c
===================================================================
RCS file: /cvs-root/kernel-source/drivers/md/md.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 md.c
--- drivers/md/md.c 30 Dec 2001 08:47:51 -0000 1.1.1.1
+++ drivers/md/md.c 13 Jan 2002 15:33:32 -0000
@@ -3302,12 +3302,15 @@
         ITERATE_RDEV(mddev,rdev,tmp) {
                 int major = MAJOR(rdev->dev);
                 int idx = disk_index(rdev->dev);
-
+ request_queue_t * rq = blk_get_queue(rdev->dev);
+
                 if ((idx >= DK_MAX_DISK) || (major >= DK_MAX_MAJOR))
                         continue;
-
- curr_events = kstat.dk_drive_rblk[major][idx] +
- kstat.dk_drive_wblk[major][idx] ;
+
+ if (rq == NULL || (rq->dk_stat == NULL))
+ continue;
+ curr_events = rq->dk_stat->dk_drive_rblk +
+ rq->dk_stat->dk_drive_wblk ;
                 curr_events -= sync_io[major][idx];
                 if ((curr_events - rdev->last_events) > 32) {
                         rdev->last_events = curr_events;
Index: fs/proc/proc_misc.c
===================================================================
RCS file: /cvs-root/kernel-source/fs/proc/proc_misc.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 proc_misc.c
--- fs/proc/proc_misc.c 30 Dec 2001 08:44:42 -0000 1.1.1.1
+++ fs/proc/proc_misc.c 13 Jan 2002 15:33:35 -0000
@@ -36,12 +36,12 @@
 #include <linux/init.h>
 #include <linux/smp_lock.h>
 #include <linux/seq_file.h>
+#include <linux/blkdev.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
 
-
 #define LOAD_INT(x) ((x) >> FSHIFT)
 #define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
 /*
@@ -234,7 +234,23 @@
         release: seq_release,
 };
 #endif
-
+static int show_disk_stat(char * page, int len, struct disk_stat * ds,
+ int major, int disk)
+{
+ int active = ds->dk_drive_rio + ds->dk_drive_wio +
+ ds->dk_drive_rblk + ds->dk_drive_wblk;
+ if (active)
+ len += sprintf(page + len,
+ "(%u,%u):(%u,%u,%u,%u,%u) ",
+ major, disk,
+ ds->dk_drive_rio + ds->dk_drive_wio,
+ ds->dk_drive_rio,
+ ds->dk_drive_rblk,
+ ds->dk_drive_wio,
+ ds->dk_drive_wblk
+ );
+ return len;
+}
 static int kstat_read_proc(char *page, char **start, off_t off,
                                  int count, int *eof, void *data)
 {
@@ -284,21 +300,27 @@
 
         len += sprintf(page + len, "\ndisk_io: ");
 
- for (major = 0; major < DK_MAX_MAJOR; major++) {
- for (disk = 0; disk < DK_MAX_DISK; disk++) {
- int active = kstat.dk_drive[major][disk] +
- kstat.dk_drive_rblk[major][disk] +
- kstat.dk_drive_wblk[major][disk];
- if (active)
- len += sprintf(page + len,
- "(%u,%u):(%u,%u,%u,%u,%u) ",
- major, disk,
- kstat.dk_drive[major][disk],
- kstat.dk_drive_rio[major][disk],
- kstat.dk_drive_rblk[major][disk],
- kstat.dk_drive_wio[major][disk],
- kstat.dk_drive_wblk[major][disk]
- );
+ for (major = 0; major < MAX_BLKDEV; major++) {
+ struct disk_stat * ds;
+
+ if (!(blk_dev[major].queue)){
+ ds = (BLK_DEFAULT_QUEUE(major))->dk_stat;
+ if (ds)
+ len = show_disk_stat(page, len, ds, major, 0);
+ }else {
+ request_queue_t * q;
+ struct gendisk * hd = get_gendisk(MKDEV(major,0));
+ int max_disk = MINORMASK>>hd->minor_shift;
+
+ for (disk = 0; disk <= max_disk; disk++) {
+ q = blk_get_queue(MKDEV(major,disk<<hd->minor_shift));
+ if (!q)
+ continue;
+ ds = q->dk_stat;
+ if (!ds)
+ continue;
+ len = show_disk_stat(page, len, ds, major,disk);
+ }
                 }
         }
 
Index: include/linux/blkdev.h
===================================================================
RCS file: /cvs-root/kernel-source/include/linux/blkdev.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 blkdev.h
--- include/linux/blkdev.h 30 Dec 2001 08:45:13 -0000 1.1.1.1
+++ include/linux/blkdev.h 13 Jan 2002 15:33:37 -0000
@@ -71,6 +71,13 @@
         struct list_head free;
 };
 
+struct disk_stat{
+ unsigned int dk_drive_rio;
+ unsigned int dk_drive_wio;
+ unsigned int dk_drive_rblk;
+ unsigned int dk_drive_wblk;
+};
+
 struct request_queue
 {
         /*
@@ -122,6 +129,10 @@
          * Tasks wait here for free request
          */
         wait_queue_head_t wait_for_request;
+ /*
+ * statistics
+ */
+ struct disk_stat * dk_stat;
 };
 
 struct blk_dev_struct {
@@ -186,7 +197,7 @@
 #define blkdev_next_request(req) blkdev_entry_to_request((req)->queue.next)
 #define blkdev_prev_request(req) blkdev_entry_to_request((req)->queue.prev)
 
-extern void drive_stat_acct (kdev_t dev, int rw,
+extern void drive_stat_acct (struct disk_stat *, int rw,
                                         unsigned long nr_sectors, int new_io);
 
 static inline int get_hardsect_size(kdev_t dev)
Index: include/linux/kernel_stat.h
===================================================================
RCS file: /cvs-root/kernel-source/include/linux/kernel_stat.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 kernel_stat.h
--- include/linux/kernel_stat.h 30 Dec 2001 08:45:14 -0000 1.1.1.1
+++ include/linux/kernel_stat.h 13 Jan 2002 15:33:37 -0000
@@ -19,11 +19,6 @@
         unsigned int per_cpu_user[NR_CPUS],
                      per_cpu_nice[NR_CPUS],
                      per_cpu_system[NR_CPUS];
- unsigned int dk_drive[DK_MAX_MAJOR][DK_MAX_DISK];
- unsigned int dk_drive_rio[DK_MAX_MAJOR][DK_MAX_DISK];
- unsigned int dk_drive_wio[DK_MAX_MAJOR][DK_MAX_DISK];
- unsigned int dk_drive_rblk[DK_MAX_MAJOR][DK_MAX_DISK];
- unsigned int dk_drive_wblk[DK_MAX_MAJOR][DK_MAX_DISK];
         unsigned int pgpgin, pgpgout;
         unsigned int pswpin, pswpout;
 #if !defined(CONFIG_ARCH_S390)

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Fri Nov 15 2002 - 22:00:27 EST