Whamcloud - gitweb
Branch HEAD
[fs/lustre-release.git] / lustre / kernel_patches / patches / sd_iostats-2.6-rhel4.patch
1 Index: linux-2.6.9-5.0.3.EL/drivers/scsi/Kconfig
2 ===================================================================
3 --- linux-2.6.9-5.0.3.EL.orig/drivers/scsi/Kconfig      2005-04-01 18:36:39.218039672 +0300
4 +++ linux-2.6.9-5.0.3.EL/drivers/scsi/Kconfig   2005-04-01 18:36:45.571073864 +0300
5 @@ -61,6 +61,14 @@
6         help
7            SCSI dump support
8  
9 +config SD_IOSTATS
10 +   bool "Enable SCSI disk I/O stats"
11 +   depends on BLK_DEV_SD
12 +   default y
13 +   ---help---
14 +     This enables SCSI disk I/O stats collection.  You must also enable
15 +     /proc file system support if you want this feature.
16 +
17  config CHR_DEV_ST
18         tristate "SCSI tape support"
19         depends on SCSI
20 Index: linux-2.6.9-5.0.3.EL/drivers/scsi/sd.c
21 ===================================================================
22 --- linux-2.6.9-5.0.3.EL.orig/drivers/scsi/sd.c 2005-04-01 18:36:39.223038912 +0300
23 +++ linux-2.6.9-5.0.3.EL/drivers/scsi/sd.c      2005-04-01 18:37:42.537413664 +0300
24 @@ -63,6 +63,38 @@
25  
26  #include "scsi_logging.h"
27  
28 +#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
29 +# include <linux/proc_fs.h>
30 +# include <linux/seq_file.h>
31 +
32 +typedef struct {
33 +        unsigned long long iostat_size;
34 +        unsigned long long iostat_count;
35 +} iostat_counter_t;
36 +
37 +#define IOSTAT_NCOUNTERS 16
38 +typedef struct {
39 +        iostat_counter_t        iostat_read_histogram[IOSTAT_NCOUNTERS];
40 +        iostat_counter_t        iostat_write_histogram[IOSTAT_NCOUNTERS];
41 +        struct timeval          iostat_timeval;
42 +} iostat_stats_t;
43 +
44 +iostat_stats_t       **sd_iostats;
45 +spinlock_t             sd_iostats_lock;
46 +struct proc_dir_entry *sd_iostats_procdir;
47 +char                   sd_iostats_procdir_name[] = "sd_iostats";
48 +
49 +extern void sd_iostats_init(void);
50 +extern void sd_iostats_init_disk(struct gendisk *);
51 +extern void sd_iostats_fini(void);
52 +extern void sd_iostats_bump(int disk, unsigned int nsect, int iswrite);
53 +#else
54 +static inline void sd_iostats_init(void) {}
55 +static inline void sd_iostats_init_disk(struct gendisk *disk) {}
56 +static inline void sd_iostats_fini(void) {}
57 +static inline void sd_iostats_bump(int disk, unsigned int nsect, int iswrite) {}
58 +#endif
59 +
60  /*
61   * More than enough for everybody ;)  The huge number of majors
62   * is a leftover from 16bit dev_t days, we don't really need that
63 @@ -76,6 +108,7 @@
64   */
65  #define SD_MAX_DISKS   (((26 * 26) + 26 + 1) * 26)
66  
67 +#define SD_STATS 256
68  /*
69   * Time out in seconds for disks and Magneto-opticals (which are slower).
70   */
71 @@ -276,6 +309,9 @@
72         SCSI_LOG_HLQUEUE(2, printk("%s : block=%llu\n",
73                                    disk->disk_name, (unsigned long long)block));
74  
75 +   sd_iostats_bump(scsi_disk(disk)->index, this_count,
76 +                   rq_data_dir(SCpnt->request) == WRITE);
77 +
78         /*
79          * If we have a 1K hardware sectorsize, prevent access to single
80          * 512 byte sectors.  In theory we could handle this - in fact
81 @@ -472,6 +508,7 @@
82                         scsi_set_medium_removal(sdev, SCSI_REMOVAL_PREVENT);
83         }
84  
85 +   sd_iostats_init_disk(disk);
86         return 0;
87  
88  error_out:
89 @@ -1573,6 +1610,327 @@
90         sd_sync_cache(sdp);
91  }      
92  
93 +#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
94 +static int
95 +sd_iostats_seq_show(struct seq_file *seq, void *v)
96 +{
97 +        struct timeval     now;
98 +        struct gendisk *disk = seq->private;
99 +        iostat_stats_t    *stats;
100 +        unsigned long long read_len;
101 +        unsigned long long read_len_tot;
102 +        unsigned long      read_num;
103 +        unsigned long      read_num_tot;
104 +        unsigned long long write_len;
105 +        unsigned long long write_len_tot;
106 +        unsigned long      write_num;
107 +        unsigned long      write_num_tot;
108 +        int                i;
109 +        int                maxi;
110 +
111 +        if (sd_iostats == NULL) {
112 +                printk(KERN_ERR "sd_iostats_seq_show: NULL stats array\n");
113 +                BUG();
114 +        }
115 +
116 +        stats = sd_iostats[scsi_disk(disk)->index];
117 +        if (stats == NULL) {
118 +                printk(KERN_ERR "sd_iostats_seq_show: NULL stats entry\n");
119 +                BUG();
120 +        }
121 +
122 +        do_gettimeofday(&now);
123 +        now.tv_sec -= stats->iostat_timeval.tv_sec;
124 +        now.tv_usec -= stats->iostat_timeval.tv_usec;
125 +        if (now.tv_usec < 0) {
126 +                now.tv_usec += 1000000;
127 +                now.tv_sec--;
128 +        }
129 +
130 +        /* this sampling races with updates */
131 +        seq_printf(seq, "index:        %lu   snapshot_time:         %lu.%06lu\n",
132 +                   scsi_disk(disk)->index, now.tv_sec, now.tv_usec);
133 +
134 +        for (i = IOSTAT_NCOUNTERS - 1; i > 0; i--)
135 +                if (stats->iostat_read_histogram[i].iostat_count != 0 ||
136 +                    stats->iostat_write_histogram[i].iostat_count != 0)
137 +                        break;
138 +        maxi = i;
139 +
140 +        seq_printf(seq, "%8s %8s %12s %8s %12s\n", "size", 
141 +                   "reads", "total", "writes", "total");
142 +
143 +        read_len_tot = write_len_tot = 0;
144 +        read_num_tot = write_num_tot = 0;
145 +        for (i = 0; i <= maxi; i++) {
146 +                read_len = stats->iostat_read_histogram[i].iostat_size;
147 +                read_len_tot += read_len;
148 +                read_num = stats->iostat_read_histogram[i].iostat_count;
149 +                read_num_tot += read_num;
150 +
151 +                write_len = stats->iostat_write_histogram[i].iostat_size;
152 +                write_len_tot += write_len;
153 +                write_num = stats->iostat_write_histogram[i].iostat_count;
154 +                write_num_tot += write_num;
155 +
156 +                seq_printf (seq, "%8d %8lu %12llu %8lu %12llu\n", 
157 +                            512<<i, read_num, read_len, write_num, write_len);
158 +        }
159 +        
160 +        seq_printf(seq, "%8s %8lu %12llu %8lu %12llu\n", "total",
161 +                   read_num_tot, read_len_tot, 
162 +                   write_num_tot, write_len_tot);
163 +        return 0;
164 +}
165 +
166 +static void *
167 +sd_iostats_seq_start(struct seq_file *p, loff_t *pos)
168 +{
169 +        return (*pos == 0) ? (void *)1 : NULL;
170 +}
171 +
172 +static void *
173 +sd_iostats_seq_next(struct seq_file *p, void *v, loff_t *pos)
174 +{
175 +        ++*pos;
176 +        return NULL;
177 +}
178 +
179 +static void
180 +sd_iostats_seq_stop(struct seq_file *p, void *v)
181 +{
182 +}
183 +
184 +static struct seq_operations sd_iostats_seqops = {
185 +        .start = sd_iostats_seq_start,
186 +        .stop  = sd_iostats_seq_stop,
187 +        .next  = sd_iostats_seq_next,
188 +        .show  = sd_iostats_seq_show,
189 +};
190 +
191 +static int
192 +sd_iostats_seq_open (struct inode *inode, struct file *file)
193 +{
194 +        int                    rc;
195 +
196 +        rc = seq_open(file, &sd_iostats_seqops);
197 +        if (rc != 0)
198 +                return rc;
199 +
200 +        ((struct seq_file *)file->private_data)->private = PDE(inode)->data;
201 +        return 0;
202 +}
203 +
204 +static ssize_t
205 +sd_iostats_seq_write(struct file *file, const char *buffer,
206 +                     size_t len, loff_t *off)
207 +{
208 +        struct seq_file   *seq = file->private_data;
209 +        struct gendisk *disk = seq->private;
210 +        iostat_stats_t    *stats = sd_iostats[scsi_disk(disk)->index];
211 +        unsigned long      flags;
212 +        
213 +        
214 +        spin_lock_irqsave (&sd_iostats_lock, flags);
215 +        memset (stats, 0, sizeof(*stats));
216 +        do_gettimeofday(&stats->iostat_timeval);
217 +        spin_unlock_irqrestore (&sd_iostats_lock, flags);
218 +
219 +        return len;
220 +}
221 +
222 +static struct file_operations sd_iostats_proc_fops = {
223 +        .owner   = THIS_MODULE,
224 +        .open    = sd_iostats_seq_open,
225 +        .read    = seq_read,
226 +        .write   = sd_iostats_seq_write,
227 +        .llseek  = seq_lseek,
228 +        .release = seq_release,
229 +};
230 +
231 +extern struct proc_dir_entry *proc_scsi;
232 +
233 +void
234 +sd_iostats_init(void)
235 +{
236 +        int    i;
237 +
238 +        spin_lock_init(&sd_iostats_lock);
239 +
240 +        sd_iostats = kmalloc(SD_STATS * sizeof(iostat_stats_t *), GFP_KERNEL);
241 +        if (sd_iostats == NULL) {
242 +                printk(KERN_WARNING "Can't keep sd iostats: "
243 +                       "ENOMEM allocating stats array size %ld\n",
244 +                       SD_STATS * sizeof(iostat_stats_t *));
245 +                return;
246 +        }
247 +
248 +        for (i = 0; i < SD_STATS; i++)
249 +                sd_iostats[i] = NULL;
250 +
251 +        if (proc_scsi == NULL) {
252 +                printk(KERN_WARNING "No access to sd iostats: "
253 +                       "proc_scsi is NULL\n");
254 +                return;
255 +        }
256 +
257 +        sd_iostats_procdir = create_proc_entry(sd_iostats_procdir_name,
258 +                                               S_IFDIR | S_IRUGO | S_IXUGO,
259 +                                               proc_scsi);
260 +        if (sd_iostats_procdir == NULL) {
261 +                printk(KERN_WARNING "No access to sd iostats: "
262 +                       "can't create /proc/scsi/%s\n", sd_iostats_procdir_name);
263 +                return;
264 +        }
265 +}
266 +
267 +void
268 +sd_iostats_init_disk(struct gendisk *disk)
269 +{
270 +        struct proc_dir_entry *pde;
271 +        unsigned long          flags;
272 +        iostat_stats_t        *stats;
273 +
274 +        if (sd_iostats == NULL ||
275 +            sd_iostats_procdir == NULL)
276 +                return;
277 +
278 +        if (scsi_disk(disk)->index > SD_STATS) {
279 +                printk(KERN_ERR "sd_iostats_init_disk: "
280 +                       "unexpected disk index %d(%d)\n",
281 +                       scsi_disk(disk)->index, SD_STATS);
282 +                                   return;
283 +        }
284 +
285 +        if (sd_iostats[scsi_disk(disk)->index] != NULL)
286 +                return;
287 +
288 +        stats = kmalloc(sizeof(*stats), GFP_KERNEL);
289 +        if (stats == NULL) {
290 +                printk(KERN_WARNING "Can't keep %s iostats: "
291 +                       "ENOMEM allocating stats size %ld\n", 
292 +                       disk->disk_name, sizeof(*stats));
293 +                return;
294 +        }
295 +
296 +        memset (stats, 0, sizeof(*stats));
297 +        do_gettimeofday(&stats->iostat_timeval);
298 +
299 +        spin_lock_irqsave(&sd_iostats_lock, flags);
300 +
301 +        if (sd_iostats[scsi_disk(disk)->index] != NULL) {
302 +                spin_unlock_irqrestore(&sd_iostats_lock, flags);
303 +                kfree (stats);
304 +                return;
305 +        }
306 +
307 +        sd_iostats[scsi_disk(disk)->index] = stats;
308 +        
309 +        spin_unlock_irqrestore(&sd_iostats_lock, flags);
310 +        
311 +        pde = create_proc_entry(disk->disk_name, S_IRUGO | S_IWUSR, 
312 +                                sd_iostats_procdir);
313 +        if (pde == NULL) {
314 +                printk(KERN_WARNING "Can't create /proc/scsi/%s/%s\n",
315 +                       sd_iostats_procdir_name, disk->disk_name);
316 +        } else {
317 +                pde->proc_fops = &sd_iostats_proc_fops;
318 +                pde->data = disk;
319 +        }
320 +}
321 +
322 +static void sd_devname(unsigned int disknum, char *buffer)
323 +{
324 +        if (disknum < 26)
325 +                sprintf(buffer, "sd%c", 'a' + disknum);
326 +        else {
327 +                unsigned int min1;
328 +                unsigned int min2;
329 +                /*
330 +                 * For larger numbers of disks, we need to go to a new
331 +                 * naming scheme.
332 +                 */
333 +                min1 = disknum / 26;
334 +                min2 = disknum % 26;
335 +                sprintf(buffer, "sd%c%c", 'a' + min1 - 1, 'a' + min2);
336 +        }
337 +}
338 +
339 +void
340 +sd_iostats_fini(void)
341 +{
342 +        char name[6];
343 +        int  i;
344 +        
345 +        if (sd_iostats_procdir != NULL) {
346 +                for (i = 0; i < SD_STATS; i++) {
347 +                        sd_devname(i, name);
348 +                        remove_proc_entry(name, sd_iostats_procdir);
349 +                }
350 +
351 +                if (proc_scsi == NULL) {
352 +                        printk(KERN_ERR "sd_iostats_fini: proc_scsi NULL\n");
353 +                        BUG();
354 +                }
355 +                remove_proc_entry(sd_iostats_procdir_name,
356 +                                  proc_scsi);
357 +
358 +                sd_iostats_procdir = NULL;
359 +        }
360 +        
361 +        if (sd_iostats != NULL) {
362 +                for (i = 0; i < SD_STATS; i++) {
363 +                        if (sd_iostats[i] != NULL)
364 +                                kfree (sd_iostats[i]);
365 +                }
366 +                
367 +                kfree(sd_iostats);
368 +                sd_iostats = NULL;
369 +        }
370 +}
371 +
372 +void
373 +sd_iostats_bump(int disk, unsigned int nsect, int iswrite)
374 +{
375 +        iostat_stats_t    *stats;
376 +        iostat_counter_t  *counter;
377 +        int                bucket;
378 +        int                tmp;
379 +        unsigned long      irqflags;
380 +
381 +        if (sd_iostats == NULL)
382 +                return;
383 +
384 +        if (disk < 0 || disk >= SD_STATS) {
385 +                printk(KERN_ERR "sd_iostats_bump: unexpected disk index %d([0-%d])\n",
386 +                       disk, SD_STATS);
387 +                BUG();
388 +        }
389 +
390 +        for (bucket = 0, tmp = nsect; tmp > 1; bucket++)
391 +                tmp /= 2;
392 +
393 +        if (bucket >= IOSTAT_NCOUNTERS) {
394 +                printk (KERN_ERR "sd_iostats_bump: nsect %d too big\n", nsect);
395 +                BUG();
396 +        }
397 +
398 +        spin_lock_irqsave(&sd_iostats_lock, irqflags);
399 +        
400 +        stats = sd_iostats[disk];
401 +        if (stats != NULL) {
402 +                counter = iswrite ? 
403 +                          &stats->iostat_write_histogram[bucket] :
404 +                          &stats->iostat_read_histogram[bucket];
405 +
406 +                counter->iostat_size += nsect;
407 +                counter->iostat_count++;
408 +        }
409 +
410 +        spin_unlock_irqrestore(&sd_iostats_lock, irqflags);
411 +}
412 +#endif
413 +
414  /**
415   *     init_sd - entry point for this driver (both when built in or when
416   *     a module).
417 @@ -1582,6 +1940,7 @@
418  static int __init init_sd(void)
419  {
420         int majors = 0, i;
421 +   int rc = 0;
422  
423         SCSI_LOG_HLQUEUE(3, printk("init_sd: sd driver entry point\n"));
424  
425 @@ -1592,7 +1951,10 @@
426         if (!majors)
427                 return -ENODEV;
428  
429 -       return scsi_register_driver(&sd_template.gendrv);
430 +   rc = scsi_register_driver(&sd_template.gendrv);
431 +   if (rc == 0)
432 +      sd_iostats_init();
433 +   return rc;
434  }
435  
436  /**
437 @@ -1606,6 +1968,7 @@
438  
439         SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n"));
440  
441 +   sd_iostats_fini();
442         scsi_unregister_driver(&sd_template.gendrv);
443         for (i = 0; i < SD_MAJORS; i++)
444                 unregister_blkdev(sd_major(i), "sd");
445 Index: linux-2.6.9-5.0.3.EL/drivers/scsi/scsi_proc.c
446 ===================================================================
447 --- linux-2.6.9-5.0.3.EL.orig/drivers/scsi/scsi_proc.c  2005-04-01 18:36:39.234037240 +0300
448 +++ linux-2.6.9-5.0.3.EL/drivers/scsi/scsi_proc.c       2005-04-01 18:36:45.578072800 +0300
449 @@ -38,7 +38,8 @@
450  /* 4K page size, but our output routines, use some slack for overruns */
451  #define PROC_BLOCK_SIZE (3*1024)
452  
453 -static struct proc_dir_entry *proc_scsi;
454 +struct proc_dir_entry *proc_scsi;
455 +EXPORT_SYMBOL(proc_scsi);
456  
457  /* Protect sht->present and sht->proc_dir */
458  static DECLARE_MUTEX(global_host_template_sem);