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