1 Index: linux-2.6.27.21-0.1/drivers/scsi/Kconfig
2 ===================================================================
3 --- linux-2.6.27.21-0.1.orig/drivers/scsi/Kconfig 2009-04-23 02:12:56.000000000 -0600
4 +++ linux-2.6.27.21-0.1/drivers/scsi/Kconfig 2009-05-22 08:38:28.000000000 -0600
6 In this case, do not compile the driver for your SCSI host adapter
7 (below) as a module either.
10 + bool "Enable SCSI disk I/O stats"
11 + depends on BLK_DEV_SD
14 + This enables SCSI disk I/O stats collection. You must also enable
15 + /proc file system support if you want this feature.
18 tristate "SCSI tape support"
20 Index: linux-2.6.27.21-0.1/drivers/scsi/scsi_proc.c
21 ===================================================================
22 --- linux-2.6.27.21-0.1.orig/drivers/scsi/scsi_proc.c 2009-04-23 02:12:56.000000000 -0600
23 +++ linux-2.6.27.21-0.1/drivers/scsi/scsi_proc.c 2009-05-22 08:38:28.000000000 -0600
25 /* 4K page size, but our output routines, use some slack for overruns */
26 #define PROC_BLOCK_SIZE (3*1024)
28 -static struct proc_dir_entry *proc_scsi;
29 +struct proc_dir_entry *proc_scsi;
30 +EXPORT_SYMBOL(proc_scsi);
32 /* Protect sht->present and sht->proc_dir */
33 static DEFINE_MUTEX(global_host_template_mutex);
34 Index: linux-2.6.27.21-0.1/drivers/scsi/sd.c
35 ===================================================================
36 --- linux-2.6.27.21-0.1.orig/drivers/scsi/sd.c 2009-04-23 02:12:56.000000000 -0600
37 +++ linux-2.6.27.21-0.1/drivers/scsi/sd.c 2009-05-22 08:38:28.000000000 -0600
39 * object after last put) */
40 static DEFINE_MUTEX(sd_ref_mutex);
42 +#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
43 +# include <linux/proc_fs.h>
44 +# include <linux/seq_file.h>
45 +struct proc_dir_entry *sd_iostats_procdir = NULL;
46 +char sd_iostats_procdir_name[] = "sd_iostats";
47 +static struct file_operations sd_iostats_proc_fops;
49 +extern void sd_iostats_init(void);
50 +extern void sd_iostats_fini(void);
51 +void sd_iostats_start_req(struct scsi_cmnd *SCpnt);
52 +void sd_iostats_finish_req(struct scsi_cmnd *SCpnt);
54 +static inline void sd_iostats_init(void) {}
55 +static inline void sd_iostats_fini(void) {}
56 +static inline void sd_iostats_start_req(struct scsi_cmnd *SCpnt) {}
57 +static inline void sd_iostats_finish_req(struct scsi_cmnd *SCpnt) {}
60 static const char *sd_cache_types[] = {
61 "write through", "none", "write back",
62 "write back, no read (daft)"
64 if (sdkp->protection_type || scsi_prot_sg_count(SCpnt))
65 sd_dif_op(SCpnt, sdkp->protection_type, scsi_prot_sg_count(SCpnt));
67 + sd_iostats_start_req(SCpnt);
70 * We shouldn't disconnect in the middle of a sector, so with a dumb
71 * host adapter, it's safe to assume that we can at least transfer
76 + sd_iostats_finish_req(SCpnt);
77 if (rq_data_dir(SCpnt->request) == READ && scsi_prot_sg_count(SCpnt))
78 sd_dif_complete(SCpnt, good_bytes);
80 @@ -1873,6 +1894,36 @@
82 gd->flags |= GENHD_FL_REMOVABLE;
84 +#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
85 + sdkp->stats = kzalloc(sizeof(iostat_stats_t), GFP_KERNEL);
87 + printk(KERN_WARNING "cannot allocate iostat structure for"
88 + "%s\n", gd->disk_name);
90 + do_gettimeofday(&sdkp->stats->iostat_timeval);
91 + sdkp->stats->iostat_queue_stamp = jiffies;
92 + spin_lock_init(&sdkp->stats->iostat_lock);
93 + if (sd_iostats_procdir) {
94 + struct proc_dir_entry *pde;
95 + pde = create_proc_entry(gd->disk_name, S_IRUGO | S_IWUSR,
96 + sd_iostats_procdir);
98 + printk(KERN_WARNING "Can't create /proc/scsi/"
100 + sd_iostats_procdir_name,
102 + kfree(sdkp->stats);
103 + sdkp->stats = NULL;
105 + pde->proc_fops = &sd_iostats_proc_fops;
109 + kfree(sdkp->stats);
110 + sdkp->stats = NULL;
114 dev_set_drvdata(dev, sdkp);
116 sd_dif_config_host(sdkp);
117 @@ -1923,6 +1974,366 @@
121 +#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
123 +sd_iostats_seq_show(struct seq_file *seq, void *v)
125 + struct timeval now;
126 + struct gendisk *disk = seq->private;
127 + iostat_stats_t *stats;
128 + unsigned long long read_len;
129 + unsigned long long read_len_tot;
130 + unsigned long read_num;
131 + unsigned long read_num_tot;
132 + unsigned long long write_len;
133 + unsigned long long write_len_tot;
134 + unsigned long write_num;
135 + unsigned long write_num_tot;
139 + stats = scsi_disk(disk)->stats;
140 + if (stats == NULL) {
141 + printk(KERN_ERR "sd_iostats_seq_show: NULL stats entry\n");
145 + do_gettimeofday(&now);
146 + now.tv_sec -= stats->iostat_timeval.tv_sec;
147 + now.tv_usec -= stats->iostat_timeval.tv_usec;
148 + if (now.tv_usec < 0) {
149 + now.tv_usec += 1000000;
153 + /* this sampling races with updates */
154 + seq_printf(seq, "index: %lu snapshot_time: %lu.%06lu\n",
155 + (unsigned long) scsi_disk(disk)->index,
156 + now.tv_sec, now.tv_usec);
158 + for (i = IOSTAT_NCOUNTERS - 1; i > 0; i--)
159 + if (stats->iostat_read_histogram[i].iostat_count != 0 ||
160 + stats->iostat_write_histogram[i].iostat_count != 0)
164 + seq_printf(seq, "%8s %8s %12s %8s %12s\n", "size",
165 + "reads", "total", "writes", "total");
167 + read_len_tot = write_len_tot = 0;
168 + read_num_tot = write_num_tot = 0;
169 + for (i = 0; i <= maxi; i++) {
170 + read_len = stats->iostat_read_histogram[i].iostat_size;
171 + read_len_tot += read_len;
172 + read_num = stats->iostat_read_histogram[i].iostat_count;
173 + read_num_tot += read_num;
175 + write_len = stats->iostat_write_histogram[i].iostat_size;
176 + write_len_tot += write_len;
177 + write_num = stats->iostat_write_histogram[i].iostat_count;
178 + write_num_tot += write_num;
180 + seq_printf (seq, "%8d %8lu %12llu %8lu %12llu\n",
181 + 512<<i, read_num, read_len, write_num, write_len);
184 + seq_printf(seq, "%8s %8lu %12llu %8lu %12llu\n\n", "total",
185 + read_num_tot, read_len_tot,
186 + write_num_tot, write_len_tot);
188 + seq_printf(seq, "%8s %8s %8s\n", "qdepth", "ticks", "%");
189 + for (i = 0; i < IOSTAT_NCOUNTERS; i++) {
190 + unsigned long long ticks, percent;
191 + ticks = stats->iostat_queue_ticks[i];
194 + percent = stats->iostat_queue_ticks[i] * 100;
195 + do_div(percent, stats->iostat_queue_ticks_sum);
196 + seq_printf(seq, "%8d %8llu %8llu\n", i, ticks, percent);
199 + if (stats->iostat_reqs != 0) {
200 + unsigned long long aveseek = 0, percent = 0;
202 + if (stats->iostat_seeks) {
203 + aveseek = stats->iostat_seek_sectors;
204 + do_div(aveseek, stats->iostat_seeks);
205 + percent = stats->iostat_seeks * 100;
206 + do_div(percent, stats->iostat_reqs);
209 + seq_printf(seq, "\n%llu sectors in %llu reqs: %llu seek(s) over "
210 + "%llu sectors in ave, %llu%% of all reqs\n",
211 + stats->iostat_sectors, stats->iostat_reqs,
212 + stats->iostat_seeks, aveseek, percent);
215 + seq_printf(seq, "\n%16s %8s %8s %8s %8s\n", "process time", "reads",
216 + "%%", "writes", "%%");
217 + for (i = 0; i < IOSTAT_NCOUNTERS; i++) {
218 + unsigned long read_percent = 0, write_percent = 0;
219 + if (stats->iostat_wtime[i] == 0 &&
220 + stats->iostat_rtime[i] == 0)
222 + if (stats->iostat_read_reqs)
223 + read_percent = stats->iostat_rtime[i] * 100 /
224 + stats->iostat_read_reqs;
225 + if (stats->iostat_write_reqs)
226 + write_percent = stats->iostat_wtime[i] * 100 /
227 + stats->iostat_write_reqs;
228 + seq_printf(seq, "%16u %8lu %8lu %8lu %8lu\n",
229 + jiffies_to_msecs(((1UL << i) >> 1) << 1),
230 + stats->iostat_rtime[i], read_percent,
231 + stats->iostat_wtime[i], write_percent);
234 + seq_printf(seq, "\n%16s %8s %8s %8s %8s\n", "time in queue", "reads",
235 + "%%", "writes", "%%");
236 + for (i = 0; i < IOSTAT_NCOUNTERS; i++) {
237 + unsigned long read_percent = 0, write_percent = 0;
238 + if (stats->iostat_wtime_in_queue[i] == 0 &&
239 + stats->iostat_rtime_in_queue[i] == 0)
241 + if (stats->iostat_read_reqs)
242 + read_percent = stats->iostat_rtime_in_queue[i] * 100 /
243 + stats->iostat_read_reqs;
244 + if (stats->iostat_write_reqs)
245 + write_percent = stats->iostat_wtime_in_queue[i] * 100 /
246 + stats->iostat_write_reqs;
247 + seq_printf(seq, "%16u %8lu %8lu %8lu %8lu\n",
248 + jiffies_to_msecs(((1UL << i) >> 1) << 1),
249 + stats->iostat_rtime_in_queue[i],
251 + stats->iostat_wtime_in_queue[i],
259 +sd_iostats_seq_start(struct seq_file *p, loff_t *pos)
261 + return (*pos == 0) ? (void *)1 : NULL;
265 +sd_iostats_seq_next(struct seq_file *p, void *v, loff_t *pos)
272 +sd_iostats_seq_stop(struct seq_file *p, void *v)
276 +static struct seq_operations sd_iostats_seqops = {
277 + .start = sd_iostats_seq_start,
278 + .stop = sd_iostats_seq_stop,
279 + .next = sd_iostats_seq_next,
280 + .show = sd_iostats_seq_show,
284 +sd_iostats_seq_open (struct inode *inode, struct file *file)
288 + rc = seq_open(file, &sd_iostats_seqops);
292 + ((struct seq_file *)file->private_data)->private = PDE(inode)->data;
297 +sd_iostats_seq_write(struct file *file, const char *buffer,
298 + size_t len, loff_t *off)
300 + struct seq_file *seq = file->private_data;
301 + struct gendisk *disk = seq->private;
302 + iostat_stats_t *stats = scsi_disk(disk)->stats;
303 + unsigned long flags;
304 + unsigned long qdepth;
307 + spin_lock_irqsave (&stats->iostat_lock, flags);
308 + qdepth = stats->iostat_queue_depth;
309 + memset (stats, 0, offsetof(iostat_stats_t, iostat_lock));
310 + do_gettimeofday(&stats->iostat_timeval);
311 + stats->iostat_queue_stamp = jiffies;
312 + stats->iostat_queue_depth = qdepth;
313 + spin_unlock_irqrestore (&stats->iostat_lock, flags);
318 +static struct file_operations sd_iostats_proc_fops = {
319 + .owner = THIS_MODULE,
320 + .open = sd_iostats_seq_open,
322 + .write = sd_iostats_seq_write,
323 + .llseek = seq_lseek,
324 + .release = seq_release,
327 +extern struct proc_dir_entry *proc_scsi;
330 +sd_iostats_init(void)
332 + if (proc_scsi == NULL) {
333 + printk(KERN_WARNING "No access to sd iostats: "
334 + "proc_scsi is NULL\n");
338 + sd_iostats_procdir = create_proc_entry(sd_iostats_procdir_name,
339 + S_IFDIR | S_IRUGO | S_IXUGO,
341 + if (sd_iostats_procdir == NULL) {
342 + printk(KERN_WARNING "No access to sd iostats: "
343 + "can't create /proc/scsi/%s\n", sd_iostats_procdir_name);
348 +void sd_iostats_fini(void)
350 + if (proc_scsi != NULL && sd_iostats_procdir != NULL)
351 + remove_proc_entry(sd_iostats_procdir_name, proc_scsi);
353 + sd_iostats_procdir = NULL;
356 +void sd_iostats_finish_req(struct scsi_cmnd *SCpnt)
358 + struct request *rq = SCpnt->request;
359 + iostat_stats_t *stats;
360 + unsigned long *tcounter;
363 + unsigned long irqflags;
366 + stats = scsi_disk(rq->rq_disk)->stats;
370 + tmp = jiffies - rq->start_time;
371 + for (tbucket = 0; tmp > 1; tbucket++)
373 + if (tbucket >= IOSTAT_NCOUNTERS)
374 + tbucket = IOSTAT_NCOUNTERS - 1;
375 + //printk("%u ticks in D to %u\n", jiffies - rq->start_time, tbucket);
377 + tcounter = rq_data_dir(rq) == WRITE ?
378 + &stats->iostat_wtime[tbucket] : &stats->iostat_rtime[tbucket];
380 + spin_lock_irqsave(&stats->iostat_lock, irqflags);
382 + /* update delay stats */
385 + /* update queue depth stats */
386 + i = stats->iostat_queue_depth;
387 + if (i >= IOSTAT_NCOUNTERS)
388 + i = IOSTAT_NCOUNTERS - 1;
389 + stats->iostat_queue_ticks[i] += jiffies - stats->iostat_queue_stamp;
390 + stats->iostat_queue_ticks_sum += jiffies - stats->iostat_queue_stamp;
391 + BUG_ON(stats->iostat_queue_depth == 0);
392 + stats->iostat_queue_depth--;
394 + /* update seek stats. XXX: not sure about nr_sectors */
395 + stats->iostat_sectors += rq->nr_sectors;
396 + stats->iostat_reqs++;
397 + if (rq->sector != stats->iostat_next_sector) {
398 + stats->iostat_seek_sectors +=
399 + rq->sector > stats->iostat_next_sector ?
400 + rq->sector - stats->iostat_next_sector :
401 + stats->iostat_next_sector - rq->sector;
402 + stats->iostat_seeks++;
404 + stats->iostat_next_sector = rq->sector + rq->nr_sectors;
406 + stats->iostat_queue_stamp = jiffies;
408 + spin_unlock_irqrestore(&stats->iostat_lock, irqflags);
411 +void sd_iostats_start_req(struct scsi_cmnd *SCpnt)
413 + struct request *rq = SCpnt->request;
414 + iostat_stats_t *stats;
415 + iostat_counter_t *counter;
419 + unsigned long irqflags;
423 + stats = scsi_disk(rq->rq_disk)->stats;
427 + nsect = scsi_bufflen(SCpnt) >> 9;
428 + for (bucket = 0, tmp = nsect; tmp > 1; bucket++)
431 + if (bucket >= IOSTAT_NCOUNTERS) {
432 + printk (KERN_ERR "sd_iostats_bump: nsect %d too big\n", nsect);
436 + counter = rq_data_dir(rq) == WRITE ?
437 + &stats->iostat_write_histogram[bucket] :
438 + &stats->iostat_read_histogram[bucket];
440 + tmp = jiffies - rq->start_time;
441 + for (tbucket = 0; tmp > 1; tbucket++)
443 + if (tbucket >= IOSTAT_NCOUNTERS)
444 + tbucket = IOSTAT_NCOUNTERS - 1;
445 + //printk("%u ticks in Q to %u\n", jiffies - rq->start_time, tbucket);
447 + /* an ugly hack to know exact processing time. the right
448 + * solution is to add one more field to struct request
449 + * hopefully it will break nothing ... */
450 + rq->start_time = jiffies;
452 + spin_lock_irqsave(&stats->iostat_lock, irqflags);
454 + /* update queue depth stats */
455 + i = stats->iostat_queue_depth;
456 + if (i >= IOSTAT_NCOUNTERS)
457 + i = IOSTAT_NCOUNTERS - 1;
458 + stats->iostat_queue_ticks[i] += jiffies - stats->iostat_queue_stamp;
459 + stats->iostat_queue_ticks_sum += jiffies - stats->iostat_queue_stamp;
460 + stats->iostat_queue_depth++;
462 + /* update delay stats */
463 + if (rq_data_dir(rq) == WRITE) {
464 + stats->iostat_wtime_in_queue[tbucket]++;
465 + stats->iostat_write_reqs++;
467 + stats->iostat_rtime_in_queue[tbucket]++;
468 + stats->iostat_read_reqs++;
471 + /* update size stats */
472 + counter->iostat_size += nsect;
473 + counter->iostat_count++;
475 + stats->iostat_queue_stamp = jiffies;
477 + spin_unlock_irqrestore(&stats->iostat_lock, irqflags);
482 * scsi_disk_release - Called to free the scsi_disk structure
483 * @dev: pointer to embedded class device
484 @@ -1941,10 +2352,16 @@
485 ida_remove(&sd_index_ida, sdkp->index);
486 spin_unlock(&sd_index_lock);
488 +#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
490 + remove_proc_entry(disk->disk_name, sd_iostats_procdir);
491 + kfree(sdkp->stats);
492 + sdkp->stats = NULL;
495 disk->private_data = NULL;
497 put_device(&sdkp->device->sdev_gendev);
502 @@ -2061,6 +2478,8 @@
508 err = class_register(&sd_disk_class);
511 @@ -2076,6 +2495,7 @@
513 for (i = 0; i < SD_MAJORS; i++)
514 unregister_blkdev(sd_major(i), "sd");
519 Index: linux-2.6.27.21-0.1/drivers/scsi/sd.h
520 ===================================================================
521 --- linux-2.6.27.21-0.1.orig/drivers/scsi/sd.h 2009-04-23 02:12:56.000000000 -0600
522 +++ linux-2.6.27.21-0.1/drivers/scsi/sd.h 2009-05-22 08:38:28.000000000 -0600
525 #define SD_LAST_BUGGY_SECTORS 8
527 +#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
529 + unsigned long long iostat_size;
530 + unsigned long long iostat_count;
533 +#define IOSTAT_NCOUNTERS 16
535 + iostat_counter_t iostat_read_histogram[IOSTAT_NCOUNTERS];
536 + iostat_counter_t iostat_write_histogram[IOSTAT_NCOUNTERS];
537 + struct timeval iostat_timeval;
539 + /* queue depth: how well the pipe is filled up */
540 + unsigned long long iostat_queue_ticks[IOSTAT_NCOUNTERS];
541 + unsigned long long iostat_queue_ticks_sum;
542 + unsigned long iostat_queue_depth;
543 + unsigned long iostat_queue_stamp;
545 + /* seeks: how linear the traffic is */
546 + unsigned long long iostat_next_sector;
547 + unsigned long long iostat_seek_sectors;
548 + unsigned long long iostat_seeks;
549 + unsigned long long iostat_sectors;
550 + unsigned long long iostat_reqs;
551 + unsigned long iostat_read_reqs;
552 + unsigned long iostat_write_reqs;
554 + /* process time: how long it takes to process requests */
555 + unsigned long iostat_rtime[IOSTAT_NCOUNTERS];
556 + unsigned long iostat_wtime[IOSTAT_NCOUNTERS];
558 + /* queue time: how long process spent in elevator's queue */
559 + unsigned long iostat_rtime_in_queue[IOSTAT_NCOUNTERS];
560 + unsigned long iostat_wtime_in_queue[IOSTAT_NCOUNTERS];
562 + /* must be the last field, as it's used to know size to be memset'ed */
563 + spinlock_t iostat_lock;
564 +} ____cacheline_aligned_in_smp iostat_stats_t;
568 struct scsi_driver *driver; /* always &sd_template */
569 struct scsi_device *device;
571 unsigned WCE : 1; /* state of disk WCE bit */
572 unsigned RCD : 1; /* state of disk RCD bit, unused */
573 unsigned DPOFUA : 1; /* state of disk DPOFUA bit */
574 +#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
575 + iostat_stats_t *stats; /* scsi disk statistics */
578 #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev)