1 Index: linux/Documentation/Configure.help
2 ===================================================================
3 RCS file: /home/cvs/master/68chaos_eebperf/Documentation/Configure.help,v
4 retrieving revision 1.1.1.1
5 diff -u -p -r1.1.1.1 Configure.help
6 --- linux/Documentation/Configure.help 20 Aug 2004 18:09:23 -0000 1.1.1.1
7 +++ linux/Documentation/Configure.help 26 Aug 2004 12:34:40 -0000
8 @@ -7679,6 +7679,11 @@ CONFIG_SCSI_LOGGING
9 there should be no noticeable performance impact as long as you have
14 + This enables SCSI disk I/O stats collection. You must also enable
15 + /proc file system support if you want this feature.
17 QDIO base support for IBM S/390 and zSeries
19 This driver provides the Queued Direct I/O base support for the
20 Index: linux/drivers/scsi/Config.in
21 ===================================================================
22 RCS file: /home/cvs/master/68chaos_eebperf/drivers/scsi/Config.in,v
23 retrieving revision 1.1.1.1
24 diff -u -p -r1.1.1.1 Config.in
25 --- linux/drivers/scsi/Config.in 20 Aug 2004 18:10:13 -0000 1.1.1.1
26 +++ linux/drivers/scsi/Config.in 24 Aug 2004 14:30:08 -0000
27 @@ -4,6 +4,7 @@ dep_tristate ' SCSI disk support' CONFI
29 if [ "$CONFIG_BLK_DEV_SD" != "n" ]; then
30 int 'Maximum number of SCSI disks that can be loaded as modules' CONFIG_SD_EXTRA_DEVS 40
31 + bool 'SCSI disk I/O stats' CONFIG_SD_IOSTATS y
34 dep_tristate ' SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI
35 Index: linux/drivers/scsi/sd.c
36 ===================================================================
37 RCS file: /home/cvs/master/68chaos_eebperf/drivers/scsi/sd.c,v
38 retrieving revision 1.1.1.1
39 diff -u -p -r1.1.1.1 sd.c
40 --- linux/drivers/scsi/sd.c 20 Aug 2004 18:10:16 -0000 1.1.1.1
41 +++ linux/drivers/scsi/sd.c 26 Aug 2004 13:34:39 -0000
43 * static const char RCSid[] = "$Header:";
46 +#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
47 +#include <linux/proc_fs.h>
48 +#include <linux/seq_file.h>
52 + unsigned long long iostat_size;
53 + unsigned long long iostat_count;
56 +#define IOSTAT_NCOUNTERS 16
59 + iostat_counter_t iostat_read_histogram[IOSTAT_NCOUNTERS];
60 + iostat_counter_t iostat_write_histogram[IOSTAT_NCOUNTERS];
61 + struct timeval iostat_timeval;
64 +iostat_stats_t **sd_iostats;
65 +spinlock_t sd_iostats_lock;
66 +struct proc_dir_entry *sd_iostats_procdir;
67 +char sd_iostats_procdir_name[] = "sd_iostats";
69 +extern void sd_iostats_init(void);
70 +extern void sd_iostats_init_disk(int disk);
71 +extern void sd_iostats_fini(void);
72 +extern void sd_iostats_bump(int disk, unsigned int nsect, int iswrite);
74 +static inline void sd_iostats_init(void) {}
75 +static inline void sd_iostats_init_disk(int disk) {}
76 +static inline void sd_iostats_fini(void) {}
77 +static inline void sd_iostats_bump(int dev, unsigned int nsect, int iswrite) {}
80 /* device number --> sd_gendisks index */
81 #define SD_MAJOR_IDX(i) ( ((MAJOR(i) & 0x80) >> 4) + (MAJOR(i) & 7) )
82 /* sd_gendisks index --> system major */
83 @@ -351,6 +385,8 @@ static int sd_init_command(Scsi_Cmnd * S
84 SCSI_LOG_HLQUEUE(2, printk("%s : real dev = /dev/%d, block = %d\n",
87 + sd_iostats_bump(dev, this_count, SCpnt->request.cmd == WRITE);
90 * If we have a 1K hardware sectorsize, prevent access to single
91 * 512 byte sectors. In theory we could handle this - in fact
92 @@ -545,7 +581,7 @@ static int sd_open(struct inode *inode,
93 if (scsi_block_when_processing_errors(SDev))
94 scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, NULL);
97 + sd_iostats_init_disk(target);
101 @@ -1179,6 +1215,8 @@ static int sd_init()
103 memset(sd_varyio, 0, (sd_template.dev_max << 4));
107 for (i = 0; i < sd_template.dev_max << 4; i++) {
108 sd_blocksizes[i] = 1024;
109 sd_hardsizes[i] = 512;
110 @@ -1243,6 +1281,7 @@ cleanup_gendisks_de_arr:
117 kfree(sd_max_sectors);
118 @@ -1466,6 +1505,316 @@ static void sd_detach(Scsi_Device * SDp)
122 +#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
124 +sd_iostats_seq_show(struct seq_file *seq, void *v)
126 + struct timeval now;
127 + unsigned long index = (unsigned long)(seq->private);
128 + iostat_stats_t *stats;
129 + unsigned long long read_len;
130 + unsigned long long read_len_tot;
131 + unsigned long read_num;
132 + unsigned long read_num_tot;
133 + unsigned long long write_len;
134 + unsigned long long write_len_tot;
135 + unsigned long write_num;
136 + unsigned long write_num_tot;
140 + if (sd_iostats == NULL) {
141 + printk(KERN_ERR "sd_iostats_seq_show: NULL stats array\n");
145 + stats = sd_iostats[index];
146 + if (stats == NULL) {
147 + printk(KERN_ERR "sd_iostats_seq_show: NULL stats entry\n");
151 + do_gettimeofday(&now);
152 + now.tv_sec -= stats->iostat_timeval.tv_sec;
153 + now.tv_usec -= stats->iostat_timeval.tv_usec;
154 + if (now.tv_usec < 0) {
155 + now.tv_usec += 1000000;
159 + /* this sampling races with updates */
160 + seq_printf(seq, "index: %lu snapshot_time: %lu.%06lu\n",
161 + index, now.tv_sec, now.tv_usec);
163 + for (i = IOSTAT_NCOUNTERS - 1; i > 0; i--)
164 + if (stats->iostat_read_histogram[i].iostat_count != 0 ||
165 + stats->iostat_write_histogram[i].iostat_count != 0)
169 + seq_printf(seq, "%8s %8s %12s %8s %12s\n", "size",
170 + "reads", "total", "writes", "total");
172 + read_len_tot = write_len_tot = 0;
173 + read_num_tot = write_num_tot = 0;
174 + for (i = 0; i <= maxi; i++) {
175 + read_len = stats->iostat_read_histogram[i].iostat_size;
176 + read_len_tot += read_len;
177 + read_num = stats->iostat_read_histogram[i].iostat_count;
178 + read_num_tot += read_num;
180 + write_len = stats->iostat_write_histogram[i].iostat_size;
181 + write_len_tot += write_len;
182 + write_num = stats->iostat_write_histogram[i].iostat_count;
183 + write_num_tot += write_num;
185 + seq_printf (seq, "%8d %8lu %12llu %8lu %12llu\n",
186 + 512<<i, read_num, read_len, write_num, write_len);
189 + seq_printf(seq, "%8s %8lu %12llu %8lu %12llu\n", "total",
190 + read_num_tot, read_len_tot,
191 + write_num_tot, write_len_tot);
196 +sd_iostats_seq_start(struct seq_file *p, loff_t *pos)
198 + return (*pos == 0) ? (void *)1 : NULL;
202 +sd_iostats_seq_next(struct seq_file *p, void *v, loff_t *pos)
209 +sd_iostats_seq_stop(struct seq_file *p, void *v)
213 +static struct seq_operations sd_iostats_seqops = {
214 + .start = sd_iostats_seq_start,
215 + .stop = sd_iostats_seq_stop,
216 + .next = sd_iostats_seq_next,
217 + .show = sd_iostats_seq_show,
221 +sd_iostats_seq_open (struct inode *inode, struct file *file)
223 + struct proc_dir_entry *dp = PDE(inode);
224 + struct seq_file *seq;
227 + rc = seq_open(file, &sd_iostats_seqops);
231 + ((struct seq_file *)file->private_data)->private = PDE(inode)->data;
236 +sd_iostats_seq_write(struct file *file, const char *buffer,
237 + size_t len, loff_t *off)
239 + struct seq_file *seq = file->private_data;
240 + unsigned long index = (unsigned long)seq->private;
241 + iostat_stats_t *stats = sd_iostats[index];
242 + unsigned long flags;
245 + spin_lock_irqsave (&sd_iostats_lock, flags);
246 + memset (stats, 0, sizeof(*stats));
247 + do_gettimeofday(&stats->iostat_timeval);
248 + spin_unlock_irqrestore (&sd_iostats_lock, flags);
253 +static struct file_operations sd_iostats_proc_fops = {
254 + .owner = THIS_MODULE,
255 + .open = sd_iostats_seq_open,
257 + .write = sd_iostats_seq_write,
258 + .llseek = seq_lseek,
259 + .release = seq_release,
263 +sd_iostats_init(void)
265 + int maxdevs = sd_template.dev_max;
268 + spin_lock_init(&sd_iostats_lock);
270 + sd_iostats = kmalloc(maxdevs * sizeof(iostat_stats_t *), GFP_KERNEL);
271 + if (sd_iostats == NULL) {
272 + printk(KERN_WARNING "Can't keep sd iostats: "
273 + "ENOMEM allocating stats array size %d\n",
274 + sd_template.dev_max * sizeof(iostat_stats_t *));
278 + for (i = 0; i < maxdevs; i++)
279 + sd_iostats[i] = NULL;
281 + if (proc_scsi == NULL) {
282 + printk(KERN_WARNING "No access to sd iostats: "
283 + "proc_scsi is NULL\n");
287 + sd_iostats_procdir = create_proc_entry(sd_iostats_procdir_name,
288 + S_IFDIR | S_IRUGO | S_IXUGO,
290 + if (sd_iostats_procdir == NULL) {
291 + printk(KERN_WARNING "No access to sd iostats: "
292 + "can't create /proc/scsi/%s\n", sd_iostats_procdir_name);
298 +sd_iostats_init_disk(int disk)
301 + struct proc_dir_entry *pde;
303 + unsigned long flags;
304 + iostat_stats_t *stats;
305 + int maxdevs = sd_template.dev_max;
307 + if (sd_iostats == NULL ||
308 + sd_iostats_procdir == NULL)
311 + if (disk > sd_template.dev_max) {
312 + printk(KERN_ERR "sd_iostats_init_disk: "
313 + "unexpected disk index %d(%d)\n",
314 + disk, sd_template.dev_max);
318 + if (sd_iostats[disk] != NULL)
321 + sd_devname(disk, name);
322 + stats = kmalloc(sizeof(*stats), GFP_KERNEL);
323 + if (stats == NULL) {
324 + printk(KERN_WARNING "Can't keep %s iostats: "
325 + "ENOMEM allocating stats size %d\n",
326 + name, sizeof(*stats));
330 + memset (stats, 0, sizeof(*stats));
331 + do_gettimeofday(&stats->iostat_timeval);
333 + spin_lock_irqsave(&sd_iostats_lock, flags);
335 + if (sd_iostats[disk] != NULL) {
336 + spin_unlock_irqrestore(&sd_iostats_lock, flags);
341 + sd_iostats[disk] = stats;
343 + spin_unlock_irqrestore(&sd_iostats_lock, flags);
345 + pde = create_proc_entry(name, S_IRUGO | S_IWUSR,
346 + sd_iostats_procdir);
348 + printk(KERN_WARNING "Can't create /proc/scsi/%s/%s\n",
349 + sd_iostats_procdir_name, name);
351 + pde->proc_fops = &sd_iostats_proc_fops;
352 + pde->data = (void *)((long)disk);
357 +sd_iostats_fini(void)
361 + int maxdevs = sd_template.dev_max;
363 + if (sd_iostats_procdir != NULL) {
364 + for (i = 0; i < maxdevs; i++) {
365 + sd_devname(i, name);
366 + remove_proc_entry(name, sd_iostats_procdir);
369 + if (proc_scsi == NULL) {
370 + printk(KERN_ERR "sd_iostats_fini: proc_scsi NULL\n");
373 + remove_proc_entry(sd_iostats_procdir_name,
376 + sd_iostats_procdir = NULL;
379 + if (sd_iostats != NULL) {
380 + for (i = 0; i < maxdevs; i++) {
381 + if (sd_iostats[i] != NULL)
382 + kfree (sd_iostats[i]);
391 +sd_iostats_bump(int disk, unsigned int nsect, int iswrite)
393 + iostat_stats_t *stats;
394 + iostat_counter_t *counter;
397 + unsigned long irqflags;
399 + if (sd_iostats == NULL)
402 + if (disk < 0 || disk >= sd_template.dev_max) {
403 + printk(KERN_ERR "sd_iostats_bump: unexpected disk index %d([0-%d])\n",
404 + disk, sd_template.dev_max);
408 + for (bucket = 0, tmp = nsect; tmp > 1; bucket++)
411 + if (bucket >= IOSTAT_NCOUNTERS) {
412 + printk (KERN_ERR "sd_iostats_bump: nsect %d too big\n", nsect);
416 + spin_lock_irqsave(&sd_iostats_lock, irqflags);
418 + stats = sd_iostats[disk];
419 + if (stats != NULL) {
420 + counter = iswrite ?
421 + &stats->iostat_write_histogram[bucket] :
422 + &stats->iostat_read_histogram[bucket];
424 + counter->iostat_size += nsect;
425 + counter->iostat_count++;
428 + spin_unlock_irqrestore(&sd_iostats_lock, irqflags);
432 static int __init init_sd(void)
434 sd_template.module = THIS_MODULE;
435 @@ -1488,6 +1837,7 @@ static void __exit exit_sd(void)
436 kfree(sd_blocksizes);
440 for (i = 0; i < N_USED_SD_MAJORS; i++) {
441 kfree(sd_gendisks[i].de_arr);
442 kfree(sd_gendisks[i].flags);