1 Index: linux-2.6.9-5.0.3.EL/drivers/scsi/Kconfig
\r
2 ===================================================================
\r
3 Index: linux+rhel4+chaos/drivers/scsi/Kconfig
4 ===================================================================
5 --- linux+rhel4+chaos.orig/drivers/scsi/Kconfig
6 +++ linux+rhel4+chaos/drivers/scsi/Kconfig
7 @@ -61,6 +61,14 @@ config SCSI_DUMP
12 + bool "Enable SCSI disk I/O stats"
13 + depends on BLK_DEV_SD
16 + This enables SCSI disk I/O stats collection. You must also enable
17 + /proc file system support if you want this feature.
20 tristate "SCSI tape support"
22 Index: linux+rhel4+chaos/drivers/scsi/sd.c
23 ===================================================================
24 --- linux+rhel4+chaos.orig/drivers/scsi/sd.c
25 +++ linux+rhel4+chaos/drivers/scsi/sd.c
28 #include "scsi_logging.h"
30 +#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
31 +# include <linux/proc_fs.h>
32 +# include <linux/seq_file.h>
35 + unsigned long long iostat_size;
36 + unsigned long long iostat_count;
39 +#define IOSTAT_NCOUNTERS 16
41 + iostat_counter_t iostat_read_histogram[IOSTAT_NCOUNTERS];
42 + iostat_counter_t iostat_write_histogram[IOSTAT_NCOUNTERS];
43 + struct timeval iostat_timeval;
46 +iostat_stats_t **sd_iostats;
47 +spinlock_t sd_iostats_lock;
48 +struct proc_dir_entry *sd_iostats_procdir;
49 +char sd_iostats_procdir_name[] = "sd_iostats";
51 +extern void sd_iostats_init(void);
52 +extern void sd_iostats_init_disk(struct gendisk *);
53 +extern void sd_iostats_fini(void);
54 +extern void sd_iostats_bump(int disk, unsigned int nsect, int iswrite);
56 +static inline void sd_iostats_init(void) {}
57 +static inline void sd_iostats_init_disk(struct gendisk *disk) {}
58 +static inline void sd_iostats_fini(void) {}
59 +static inline void sd_iostats_bump(int disk, unsigned int nsect, int iswrite) {}
63 * More than enough for everybody ;) The huge number of majors
64 * is a leftover from 16bit dev_t days, we don't really need that
67 #define SD_MAX_DISKS (((26 * 26) + 26 + 1) * 26)
71 * Time out in seconds for disks and Magneto-opticals (which are slower).
73 @@ -278,6 +311,9 @@ static int sd_init_command(struct scsi_c
74 SCSI_LOG_HLQUEUE(2, printk("%s : block=%llu\n",
75 disk->disk_name, (unsigned long long)block));
77 + sd_iostats_bump(scsi_disk(disk)->index, this_count,
78 + rq_data_dir(SCpnt->request) == WRITE);
81 * If we have a 1K hardware sectorsize, prevent access to single
82 * 512 byte sectors. In theory we could handle this - in fact
83 @@ -474,6 +510,7 @@ static int sd_open(struct inode *inode,
84 scsi_set_medium_removal(sdev, SCSI_REMOVAL_PREVENT);
87 + sd_iostats_init_disk(disk);
91 @@ -500,8 +537,20 @@ static int sd_release(struct inode *inod
93 SCSI_LOG_HLQUEUE(3, printk("sd_release: disk=%s\n", disk->disk_name));
95 - if (!--sdkp->openers && sdev->removable) {
96 - if (scsi_block_when_processing_errors(sdev))
97 + if (!--sdkp->openers) {
99 + * Remove sd_iostats information about this disk
101 + if (sd_iostats_procdir != NULL) {
102 + remove_proc_entry(disk->disk_name, sd_iostats_procdir);
104 + if (sd_iostats != NULL) {
105 + if (sd_iostats[sdkp->index] != NULL) {
106 + kfree (sd_iostats[sdkp->index]);
107 + sd_iostats[sdkp->index] = NULL;
110 + if (sdev->removable && scsi_block_when_processing_errors(sdev))
111 scsi_set_medium_removal(sdev, SCSI_REMOVAL_ALLOW);
114 @@ -1575,6 +1624,342 @@ static void sd_shutdown(struct device *d
118 +#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
120 +sd_iostats_seq_show(struct seq_file *seq, void *v)
122 + struct timeval now;
123 + struct gendisk *disk;
124 + iostat_stats_t *stats;
125 + unsigned long long read_len;
126 + unsigned long long read_len_tot;
127 + unsigned long read_num;
128 + unsigned long read_num_tot;
129 + unsigned long long write_len;
130 + unsigned long long write_len_tot;
131 + unsigned long write_num;
132 + unsigned long write_num_tot;
136 + if (seq == NULL || seq->private == NULL) {
137 + printk(KERN_ERR "sd_iostats_seq_show: NULL disk\n");
141 + disk = seq->private;
143 + if (scsi_disk(disk) == NULL || (disk->flags & GENHD_FL_UP) == 0) {
144 + seq_printf(seq, "sd_iostats_seq_show: Device %s "
145 + "does not exist\n", disk->disk_name);
149 + if (sd_iostats == NULL) {
150 + printk(KERN_ERR "sd_iostats_seq_show: NULL stats array\n");
154 + stats = sd_iostats[scsi_disk(disk)->index];
155 + if (stats == NULL) {
156 + seq_printf(seq, "sd_iostats_seq_show: sd_iostats "
157 + "entry %d does not exist\n",
158 + scsi_disk(disk)->index);
162 + do_gettimeofday(&now);
163 + now.tv_sec -= stats->iostat_timeval.tv_sec;
164 + now.tv_usec -= stats->iostat_timeval.tv_usec;
165 + if (now.tv_usec < 0) {
166 + now.tv_usec += 1000000;
170 + /* this sampling races with updates */
171 + seq_printf(seq, "index: %lu snapshot_time: %lu.%06lu\n",
172 + scsi_disk(disk)->index, now.tv_sec, now.tv_usec);
174 + for (i = IOSTAT_NCOUNTERS - 1; i > 0; i--)
175 + if (stats->iostat_read_histogram[i].iostat_count != 0 ||
176 + stats->iostat_write_histogram[i].iostat_count != 0)
180 + seq_printf(seq, "%8s %8s %12s %8s %12s\n", "size",
181 + "reads", "total", "writes", "total");
183 + read_len_tot = write_len_tot = 0;
184 + read_num_tot = write_num_tot = 0;
185 + for (i = 0; i <= maxi; i++) {
186 + read_len = stats->iostat_read_histogram[i].iostat_size;
187 + read_len_tot += read_len;
188 + read_num = stats->iostat_read_histogram[i].iostat_count;
189 + read_num_tot += read_num;
191 + write_len = stats->iostat_write_histogram[i].iostat_size;
192 + write_len_tot += write_len;
193 + write_num = stats->iostat_write_histogram[i].iostat_count;
194 + write_num_tot += write_num;
196 + seq_printf (seq, "%8d %8lu %12llu %8lu %12llu\n",
197 + 512<<i, read_num, read_len, write_num, write_len);
200 + seq_printf(seq, "%8s %8lu %12llu %8lu %12llu\n", "total",
201 + read_num_tot, read_len_tot,
202 + write_num_tot, write_len_tot);
207 +sd_iostats_seq_start(struct seq_file *p, loff_t *pos)
209 + return (*pos == 0) ? (void *)1 : NULL;
213 +sd_iostats_seq_next(struct seq_file *p, void *v, loff_t *pos)
220 +sd_iostats_seq_stop(struct seq_file *p, void *v)
224 +static struct seq_operations sd_iostats_seqops = {
225 + .start = sd_iostats_seq_start,
226 + .stop = sd_iostats_seq_stop,
227 + .next = sd_iostats_seq_next,
228 + .show = sd_iostats_seq_show,
232 +sd_iostats_seq_open (struct inode *inode, struct file *file)
236 + rc = seq_open(file, &sd_iostats_seqops);
240 + ((struct seq_file *)file->private_data)->private = PDE(inode)->data;
245 +sd_iostats_seq_write(struct file *file, const char *buffer,
246 + size_t len, loff_t *off)
248 + struct seq_file *seq = file->private_data;
249 + struct gendisk *disk = seq->private;
250 + iostat_stats_t *stats = sd_iostats[scsi_disk(disk)->index];
251 + unsigned long flags;
254 + spin_lock_irqsave (&sd_iostats_lock, flags);
255 + memset (stats, 0, sizeof(*stats));
256 + do_gettimeofday(&stats->iostat_timeval);
257 + spin_unlock_irqrestore (&sd_iostats_lock, flags);
262 +static struct file_operations sd_iostats_proc_fops = {
263 + .owner = THIS_MODULE,
264 + .open = sd_iostats_seq_open,
266 + .write = sd_iostats_seq_write,
267 + .llseek = seq_lseek,
268 + .release = seq_release,
271 +extern struct proc_dir_entry *proc_scsi;
274 +sd_iostats_init(void)
278 + spin_lock_init(&sd_iostats_lock);
280 + sd_iostats = kmalloc(SD_STATS * sizeof(iostat_stats_t *), GFP_KERNEL);
281 + if (sd_iostats == NULL) {
282 + printk(KERN_WARNING "Can't keep sd iostats: "
283 + "ENOMEM allocating stats array size %ld\n",
284 + SD_STATS * sizeof(iostat_stats_t *));
288 + for (i = 0; i < SD_STATS; i++)
289 + sd_iostats[i] = NULL;
291 + if (proc_scsi == NULL) {
292 + printk(KERN_WARNING "No access to sd iostats: "
293 + "proc_scsi is NULL\n");
297 + sd_iostats_procdir = create_proc_entry(sd_iostats_procdir_name,
298 + S_IFDIR | S_IRUGO | S_IXUGO,
300 + if (sd_iostats_procdir == NULL) {
301 + printk(KERN_WARNING "No access to sd iostats: "
302 + "can't create /proc/scsi/%s\n", sd_iostats_procdir_name);
308 +sd_iostats_init_disk(struct gendisk *disk)
310 + struct proc_dir_entry *pde;
311 + unsigned long flags;
312 + iostat_stats_t *stats;
314 + if (sd_iostats == NULL ||
315 + sd_iostats_procdir == NULL)
318 + if (scsi_disk(disk)->index > SD_STATS) {
319 + printk(KERN_ERR "sd_iostats_init_disk: "
320 + "unexpected disk index %d(%d)\n",
321 + scsi_disk(disk)->index, SD_STATS);
325 + if (sd_iostats[scsi_disk(disk)->index] != NULL)
328 + stats = kmalloc(sizeof(*stats), GFP_KERNEL);
329 + if (stats == NULL) {
330 + printk(KERN_WARNING "Can't keep %s iostats: "
331 + "ENOMEM allocating stats size %ld\n",
332 + disk->disk_name, sizeof(*stats));
336 + memset (stats, 0, sizeof(*stats));
337 + do_gettimeofday(&stats->iostat_timeval);
339 + spin_lock_irqsave(&sd_iostats_lock, flags);
341 + if (sd_iostats[scsi_disk(disk)->index] != NULL) {
342 + spin_unlock_irqrestore(&sd_iostats_lock, flags);
347 + sd_iostats[scsi_disk(disk)->index] = stats;
349 + spin_unlock_irqrestore(&sd_iostats_lock, flags);
351 + pde = create_proc_entry(disk->disk_name, S_IRUGO | S_IWUSR,
352 + sd_iostats_procdir);
354 + printk(KERN_WARNING "Can't create /proc/scsi/%s/%s\n",
355 + sd_iostats_procdir_name, disk->disk_name);
357 + pde->proc_fops = &sd_iostats_proc_fops;
362 +static void sd_devname(unsigned int disknum, char *buffer)
365 + sprintf(buffer, "sd%c", 'a' + disknum);
370 + * For larger numbers of disks, we need to go to a new
373 + min1 = disknum / 26;
374 + min2 = disknum % 26;
375 + sprintf(buffer, "sd%c%c", 'a' + min1 - 1, 'a' + min2);
380 +sd_iostats_fini(void)
385 + if (sd_iostats_procdir != NULL) {
386 + for (i = 0; i < SD_STATS; i++) {
387 + sd_devname(i, name);
388 + remove_proc_entry(name, sd_iostats_procdir);
391 + if (proc_scsi == NULL) {
392 + printk(KERN_ERR "sd_iostats_fini: proc_scsi NULL\n");
395 + remove_proc_entry(sd_iostats_procdir_name,
398 + sd_iostats_procdir = NULL;
401 + if (sd_iostats != NULL) {
402 + for (i = 0; i < SD_STATS; i++) {
403 + if (sd_iostats[i] != NULL)
404 + kfree (sd_iostats[i]);
413 +sd_iostats_bump(int disk, unsigned int nsect, int iswrite)
415 + iostat_stats_t *stats;
416 + iostat_counter_t *counter;
419 + unsigned long irqflags;
421 + if (sd_iostats == NULL)
424 + if (disk < 0 || disk >= SD_STATS) {
425 + printk(KERN_ERR "sd_iostats_bump: unexpected disk index %d([0-%d])\n",
430 + for (bucket = 0, tmp = nsect; tmp > 1; bucket++)
433 + if (bucket >= IOSTAT_NCOUNTERS) {
434 + printk (KERN_ERR "sd_iostats_bump: nsect %d too big\n", nsect);
438 + spin_lock_irqsave(&sd_iostats_lock, irqflags);
440 + stats = sd_iostats[disk];
441 + if (stats != NULL) {
442 + counter = iswrite ?
443 + &stats->iostat_write_histogram[bucket] :
444 + &stats->iostat_read_histogram[bucket];
446 + counter->iostat_size += nsect;
447 + counter->iostat_count++;
450 + spin_unlock_irqrestore(&sd_iostats_lock, irqflags);
455 * init_sd - entry point for this driver (both when built in or when
457 @@ -1584,6 +1969,7 @@ static void sd_shutdown(struct device *d
458 static int __init init_sd(void)
463 SCSI_LOG_HLQUEUE(3, printk("init_sd: sd driver entry point\n"));
465 @@ -1594,7 +1980,10 @@ static int __init init_sd(void)
469 - return scsi_register_driver(&sd_template.gendrv);
470 + rc = scsi_register_driver(&sd_template.gendrv);
477 @@ -1608,6 +1997,7 @@ static void __exit exit_sd(void)
479 SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n"));
482 scsi_unregister_driver(&sd_template.gendrv);
483 for (i = 0; i < SD_MAJORS; i++)
484 unregister_blkdev(sd_major(i), "sd");
485 Index: linux+rhel4+chaos/drivers/scsi/scsi_proc.c
486 ===================================================================
487 --- linux+rhel4+chaos.orig/drivers/scsi/scsi_proc.c
488 +++ linux+rhel4+chaos/drivers/scsi/scsi_proc.c
490 /* 4K page size, but our output routines, use some slack for overruns */
491 #define PROC_BLOCK_SIZE (3*1024)
493 -static struct proc_dir_entry *proc_scsi;
494 +struct proc_dir_entry *proc_scsi;
495 +EXPORT_SYMBOL(proc_scsi);
497 /* Protect sht->present and sht->proc_dir */
498 static DECLARE_MUTEX(global_host_template_sem);