Whamcloud - gitweb
Branch HEAD
[fs/lustre-release.git] / lustre / kernel_patches / patches / sd_iostats-2.4.21-chaos.patch
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
10    logging turned off.
11  
12 +SCSI disk I/O stats
13 +CONFIG_SD_IOSTATS
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  QDIO base support for IBM S/390 and zSeries
18  CONFIG_QDIO
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
28  
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
32  fi
33  
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
42 @@ -65,6 +65,40 @@
43   *  static const char RCSid[] = "$Header:";
44   */
45  
46 +#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
47 +#include <linux/proc_fs.h>
48 +#include <linux/seq_file.h>
49 +
50 +typedef struct
51 +{
52 +        unsigned long long      iostat_size;
53 +        unsigned long long      iostat_count;
54 +} iostat_counter_t;
55 +
56 +#define IOSTAT_NCOUNTERS 16
57 +typedef struct 
58 +{
59 +        iostat_counter_t        iostat_read_histogram[IOSTAT_NCOUNTERS];
60 +        iostat_counter_t        iostat_write_histogram[IOSTAT_NCOUNTERS];
61 +       struct timeval          iostat_timeval;
62 +} iostat_stats_t;
63 +        
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";
68 +
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);
73 +#else
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) {}
78 +#endif
79 +
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",
85                                    nbuff, dev, block));
86  
87 +       sd_iostats_bump(dev, this_count, SCpnt->request.cmd == WRITE);
88 +
89         /*
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);
95  
96 -       
97 +       sd_iostats_init_disk(target);
98         return 0;
99  
100  error_out:
101 @@ -1179,6 +1215,8 @@ static int sd_init()
102  
103         memset(sd_varyio, 0, (sd_template.dev_max << 4)); 
104  
105 +       sd_iostats_init();
106 +
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:
111         kfree(sd_gendisks);
112         sd_gendisks = NULL;
113  cleanup_sd_gendisks:
114 +       sd_iostats_fini();
115         kfree(sd_varyio);
116  cleanup_varyio:
117         kfree(sd_max_sectors);
118 @@ -1466,6 +1505,316 @@ static void sd_detach(Scsi_Device * SDp)
119         return;
120  }
121  
122 +#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
123 +static int
124 +sd_iostats_seq_show(struct seq_file *seq, void *v)
125 +{
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;
137 +        int                i;
138 +       int                maxi;
139 +
140 +       if (sd_iostats == NULL) {
141 +               printk(KERN_ERR "sd_iostats_seq_show: NULL stats array\n");
142 +               BUG();
143 +       }
144 +
145 +       stats = sd_iostats[index];
146 +       if (stats == NULL) {
147 +               printk(KERN_ERR "sd_iostats_seq_show: NULL stats entry\n");
148 +               BUG();
149 +       }
150 +
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;
156 +               now.tv_sec--;
157 +       }
158 +
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);
162 +
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)
166 +                       break;
167 +       maxi = i;
168 +
169 +       seq_printf(seq, "%8s %8s %12s %8s %12s\n", "size", 
170 +                  "reads", "total", "writes", "total");
171 +
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;
179 +
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;
184 +
185 +               seq_printf (seq, "%8d %8lu %12llu %8lu %12llu\n", 
186 +                           512<<i, read_num, read_len, write_num, write_len);
187 +       }
188 +       
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);
192 +        return 0;
193 +}
194 +
195 +static void *
196 +sd_iostats_seq_start(struct seq_file *p, loff_t *pos)
197 +{
198 +        return (*pos == 0) ? (void *)1 : NULL;
199 +}
200 +
201 +static void *
202 +sd_iostats_seq_next(struct seq_file *p, void *v, loff_t *pos)
203 +{
204 +        ++*pos;
205 +        return NULL;
206 +}
207 +
208 +static void
209 +sd_iostats_seq_stop(struct seq_file *p, void *v)
210 +{
211 +}
212 +
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,
218 +};
219 +
220 +static int
221 +sd_iostats_seq_open (struct inode *inode, struct file *file)
222 +{
223 +       struct proc_dir_entry *dp = PDE(inode);
224 +       struct seq_file       *seq;
225 +       int                    rc;
226 +
227 +       rc = seq_open(file, &sd_iostats_seqops);
228 +       if (rc != 0)
229 +               return rc;
230 +
231 +       ((struct seq_file *)file->private_data)->private = PDE(inode)->data;
232 +       return 0;
233 +}
234 +
235 +static int
236 +sd_iostats_seq_write(struct file *file, const char *buffer,
237 +                    size_t len, loff_t *off)
238 +{
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;
243 +       
244 +       
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);
249 +
250 +       return len;
251 +}
252 +
253 +static struct file_operations sd_iostats_proc_fops = {
254 +        .owner   = THIS_MODULE,
255 +        .open    = sd_iostats_seq_open,
256 +        .read    = seq_read,
257 +        .write   = sd_iostats_seq_write,
258 +        .llseek  = seq_lseek,
259 +        .release = seq_release,
260 +};
261 +
262 +void
263 +sd_iostats_init(void)
264 +{
265 +       int    maxdevs = sd_template.dev_max;
266 +       int    i;
267 +
268 +       spin_lock_init(&sd_iostats_lock);
269 +
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 *));
275 +               return;
276 +       }
277 +
278 +       for (i = 0; i < maxdevs; i++)
279 +               sd_iostats[i] = NULL;
280 +
281 +       if (proc_scsi == NULL) {
282 +               printk(KERN_WARNING "No access to sd iostats: "
283 +                      "proc_scsi is NULL\n");
284 +               return;
285 +       }
286 +
287 +       sd_iostats_procdir = create_proc_entry(sd_iostats_procdir_name,
288 +                                              S_IFDIR | S_IRUGO | S_IXUGO,
289 +                                              proc_scsi);
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);
293 +               return;
294 +       }
295 +}
296 +
297 +void
298 +sd_iostats_init_disk(int disk)
299 +{
300 +       char                   name[6];
301 +       struct proc_dir_entry *pde;
302 +       int                    i;
303 +       unsigned long          flags;
304 +       iostat_stats_t        *stats;
305 +       int                    maxdevs = sd_template.dev_max;
306 +
307 +       if (sd_iostats == NULL ||
308 +           sd_iostats_procdir == NULL)
309 +               return;
310 +
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);
315 +               BUG();
316 +       }
317 +
318 +       if (sd_iostats[disk] != NULL)
319 +               return;
320 +
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));
327 +               return;
328 +       }
329 +
330 +       memset (stats, 0, sizeof(*stats));
331 +       do_gettimeofday(&stats->iostat_timeval);
332 +
333 +       spin_lock_irqsave(&sd_iostats_lock, flags);
334 +
335 +       if (sd_iostats[disk] != NULL) {
336 +               spin_unlock_irqrestore(&sd_iostats_lock, flags);
337 +               kfree (stats);
338 +               return;
339 +       }
340 +
341 +       sd_iostats[disk] = stats;
342 +       
343 +       spin_unlock_irqrestore(&sd_iostats_lock, flags);
344 +       
345 +       pde = create_proc_entry(name, S_IRUGO | S_IWUSR, 
346 +                               sd_iostats_procdir);
347 +       if (pde == NULL) {
348 +               printk(KERN_WARNING "Can't create /proc/scsi/%s/%s\n",
349 +                      sd_iostats_procdir_name, name);
350 +       } else {
351 +               pde->proc_fops = &sd_iostats_proc_fops;
352 +               pde->data = (void *)((long)disk);
353 +       }
354 +}
355 +
356 +void
357 +sd_iostats_fini(void)
358 +{
359 +       char name[6];
360 +       int  i;
361 +       int  maxdevs = sd_template.dev_max;
362 +       
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);
367 +               }
368 +
369 +               if (proc_scsi == NULL) {
370 +                       printk(KERN_ERR "sd_iostats_fini: proc_scsi NULL\n");
371 +                       BUG();
372 +               }
373 +               remove_proc_entry(sd_iostats_procdir_name,
374 +                                 proc_scsi);
375 +
376 +               sd_iostats_procdir = NULL;
377 +       }
378 +       
379 +       if (sd_iostats != NULL) {
380 +               for (i = 0; i < maxdevs; i++) {
381 +                       if (sd_iostats[i] != NULL)
382 +                               kfree (sd_iostats[i]);
383 +               }
384 +               
385 +               kfree(sd_iostats);
386 +               sd_iostats = NULL;
387 +       }
388 +}
389 +
390 +void
391 +sd_iostats_bump(int disk, unsigned int nsect, int iswrite)
392 +{
393 +       iostat_stats_t    *stats;
394 +       iostat_counter_t  *counter;
395 +       int                bucket;
396 +       int                tmp;
397 +       unsigned long      irqflags;
398 +
399 +       if (sd_iostats == NULL)
400 +               return;
401 +
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);
405 +               BUG();
406 +       }
407 +
408 +       for (bucket = 0, tmp = nsect; tmp > 1; bucket++)
409 +               tmp /= 2;
410 +
411 +       if (bucket >= IOSTAT_NCOUNTERS) {
412 +               printk (KERN_ERR "sd_iostats_bump: nsect %d too big\n", nsect);
413 +               BUG();
414 +       }
415 +
416 +       spin_lock_irqsave(&sd_iostats_lock, irqflags);
417 +       
418 +       stats = sd_iostats[disk];
419 +       if (stats != NULL) {
420 +               counter = iswrite ? 
421 +                         &stats->iostat_write_histogram[bucket] :
422 +                         &stats->iostat_read_histogram[bucket];
423 +
424 +               counter->iostat_size += nsect;
425 +               counter->iostat_count++;
426 +       }
427 +
428 +       spin_unlock_irqrestore(&sd_iostats_lock, irqflags);
429 +}
430 +#endif
431 +
432  static int __init init_sd(void)
433  {
434         sd_template.module = THIS_MODULE;
435 @@ -1488,6 +1837,7 @@ static void __exit exit_sd(void)
436                 kfree(sd_blocksizes);
437                 kfree(sd_hardsizes);
438                 kfree(sd_varyio);
439 +               sd_iostats_fini();
440                 for (i = 0; i < N_USED_SD_MAJORS; i++) {
441                         kfree(sd_gendisks[i].de_arr);
442                         kfree(sd_gendisks[i].flags);