Whamcloud - gitweb
b=20595
[fs/lustre-release.git] / lustre / kernel_patches / patches / sd_iostats-2.6.27-vanilla.patch
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
5 @@ -82,6 +82,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.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
24 @@ -40,7 +40,8 @@
25  /* 4K page size, but our output routines, use some slack for overruns */
26  #define PROC_BLOCK_SIZE (3*1024)
27  
28 -static struct proc_dir_entry *proc_scsi;
29 +struct proc_dir_entry *proc_scsi;
30 +EXPORT_SYMBOL(proc_scsi);
31  
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
38 @@ -108,6 +108,24 @@
39   * object after last put) */
40  static DEFINE_MUTEX(sd_ref_mutex);
41  
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;
48 +
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);
53 +#else
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) {}
58 +#endif
59 +
60  static const char *sd_cache_types[] = {
61         "write through", "none", "write back",
62         "write back, no read (daft)"
63 @@ -571,6 +589,8 @@
64         if (sdkp->protection_type || scsi_prot_sg_count(SCpnt))
65                 sd_dif_op(SCpnt, sdkp->protection_type, scsi_prot_sg_count(SCpnt));
66  
67 +       sd_iostats_start_req(SCpnt);
68 +
69         /*
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
72 @@ -1091,6 +1111,7 @@
73                 break;
74         }
75   out:
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);
79  
80 @@ -1873,6 +1894,36 @@
81         if (sdp->removable)
82                 gd->flags |= GENHD_FL_REMOVABLE;
83  
84 +#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
85 +       sdkp->stats = kzalloc(sizeof(iostat_stats_t), GFP_KERNEL);
86 +       if (!sdkp->stats) {
87 +               printk(KERN_WARNING "cannot allocate iostat structure for"
88 +                                   "%s\n", gd->disk_name);
89 +       } else {
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);
97 +                       if (!pde) {
98 +                               printk(KERN_WARNING "Can't create /proc/scsi/"
99 +                                                   "%s/%s\n",
100 +                                                   sd_iostats_procdir_name,
101 +                                                   gd->disk_name);
102 +                               kfree(sdkp->stats);
103 +                               sdkp->stats = NULL;
104 +                       } else {
105 +                               pde->proc_fops = &sd_iostats_proc_fops;
106 +                               pde->data = gd;
107 +                       }
108 +               } else {
109 +                       kfree(sdkp->stats);
110 +                       sdkp->stats = NULL;
111 +               }
112 +       }
113 +#endif
114         dev_set_drvdata(dev, sdkp);
115         add_disk(gd);
116         sd_dif_config_host(sdkp);
117 @@ -1923,6 +1974,366 @@
118         return 0;
119  }
120  
121 +#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
122 +static int
123 +sd_iostats_seq_show(struct seq_file *seq, void *v)
124 +{
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;
136 +       int                i;
137 +       int                maxi;
138 +
139 +       stats = scsi_disk(disk)->stats;
140 +       if (stats == NULL) {
141 +               printk(KERN_ERR "sd_iostats_seq_show: NULL stats entry\n");
142 +               BUG();
143 +       }
144 +
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;
150 +               now.tv_sec--;
151 +       }
152 +
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);
157 +
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)
161 +                       break;
162 +       maxi = i;
163 +
164 +       seq_printf(seq, "%8s %8s %12s %8s %12s\n", "size", 
165 +                       "reads", "total", "writes", "total");
166 +
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;
174 +
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;
179 +
180 +               seq_printf (seq, "%8d %8lu %12llu %8lu %12llu\n", 
181 +                               512<<i, read_num, read_len, write_num, write_len);
182 +       }
183 +
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);
187 +
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];
192 +               if (ticks == 0)
193 +                       continue;
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);
197 +       }
198 +
199 +       if (stats->iostat_reqs != 0) {
200 +               unsigned long long aveseek = 0, percent = 0;
201 +
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);
207 +               }
208 +
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);
213 +       }
214 +
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)
221 +                       continue;
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);
232 +       }
233 +
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)
240 +                       continue;
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],
250 +                               read_percent,
251 +                               stats->iostat_wtime_in_queue[i],
252 +                               write_percent);
253 +       }
254 +
255 +       return 0;
256 +}
257 +
258 +static void *
259 +sd_iostats_seq_start(struct seq_file *p, loff_t *pos)
260 +{
261 +       return (*pos == 0) ? (void *)1 : NULL;
262 +}
263 +
264 +static void *
265 +sd_iostats_seq_next(struct seq_file *p, void *v, loff_t *pos)
266 +{
267 +       ++*pos;
268 +       return NULL;
269 +}
270 +
271 +static void
272 +sd_iostats_seq_stop(struct seq_file *p, void *v)
273 +{
274 +}
275 +
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,
281 +};
282 +
283 +static int
284 +sd_iostats_seq_open (struct inode *inode, struct file *file)
285 +{
286 +       int rc;
287 +
288 +       rc = seq_open(file, &sd_iostats_seqops);
289 +       if (rc != 0)
290 +               return rc;
291 +
292 +       ((struct seq_file *)file->private_data)->private = PDE(inode)->data;
293 +       return 0;
294 +}
295 +
296 +static ssize_t
297 +sd_iostats_seq_write(struct file *file, const char *buffer,
298 +                    size_t len, loff_t *off)
299 +{
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;
305 +
306 +
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);
314 +
315 +       return len;
316 +}
317 +
318 +static struct file_operations sd_iostats_proc_fops = {
319 +       .owner   = THIS_MODULE,
320 +       .open    = sd_iostats_seq_open,
321 +       .read    = seq_read,
322 +       .write   = sd_iostats_seq_write,
323 +       .llseek  = seq_lseek,
324 +       .release = seq_release,
325 +};
326 +
327 +extern struct proc_dir_entry *proc_scsi;
328 +
329 +void
330 +sd_iostats_init(void)
331 +{
332 +       if (proc_scsi == NULL) {
333 +               printk(KERN_WARNING "No access to sd iostats: "
334 +                       "proc_scsi is NULL\n");
335 +               return;
336 +       }
337 +
338 +       sd_iostats_procdir = create_proc_entry(sd_iostats_procdir_name,
339 +                                              S_IFDIR | S_IRUGO | S_IXUGO,
340 +                                               proc_scsi);
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);
344 +               return;
345 +       }
346 +}
347 +
348 +void sd_iostats_fini(void)
349 +{
350 +       if (proc_scsi != NULL && sd_iostats_procdir != NULL)
351 +               remove_proc_entry(sd_iostats_procdir_name, proc_scsi);
352 +
353 +       sd_iostats_procdir = NULL;
354 +}
355 +
356 +void sd_iostats_finish_req(struct scsi_cmnd *SCpnt)
357 +{
358 +       struct request          *rq = SCpnt->request;
359 +       iostat_stats_t          *stats;
360 +       unsigned long           *tcounter;
361 +       int                     tbucket;
362 +       int                     tmp;
363 +       unsigned long           irqflags;
364 +       unsigned long           i;
365 +
366 +       stats = scsi_disk(rq->rq_disk)->stats;
367 +       if (stats == NULL)
368 +               return;
369 +
370 +       tmp = jiffies - rq->start_time;
371 +       for (tbucket = 0; tmp > 1; tbucket++)
372 +               tmp >>= 1;
373 +       if (tbucket >= IOSTAT_NCOUNTERS)
374 +               tbucket = IOSTAT_NCOUNTERS - 1;
375 +       //printk("%u ticks in D to %u\n", jiffies - rq->start_time, tbucket);
376 +
377 +       tcounter = rq_data_dir(rq) == WRITE ?
378 +               &stats->iostat_wtime[tbucket] : &stats->iostat_rtime[tbucket];
379 +
380 +       spin_lock_irqsave(&stats->iostat_lock, irqflags);
381 +
382 +       /* update delay stats */
383 +       (*tcounter)++;
384 +
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--;
393 +
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++;
403 +       }
404 +       stats->iostat_next_sector = rq->sector + rq->nr_sectors;
405 +
406 +       stats->iostat_queue_stamp = jiffies;
407 +
408 +       spin_unlock_irqrestore(&stats->iostat_lock, irqflags);
409 +}
410 +
411 +void sd_iostats_start_req(struct scsi_cmnd *SCpnt)
412 +{
413 +       struct request          *rq = SCpnt->request;
414 +       iostat_stats_t          *stats;
415 +       iostat_counter_t        *counter;
416 +       int                     bucket;
417 +       int                     tbucket;
418 +       int                     tmp;
419 +       unsigned long           irqflags;
420 +       unsigned long           i;
421 +       int                     nsect;
422 +
423 +       stats = scsi_disk(rq->rq_disk)->stats;
424 +       if (stats == NULL)
425 +               return;
426 +
427 +       nsect = scsi_bufflen(SCpnt) >> 9;
428 +       for (bucket = 0, tmp = nsect; tmp > 1; bucket++)
429 +               tmp >>= 1;
430 +
431 +       if (bucket >= IOSTAT_NCOUNTERS) {
432 +               printk (KERN_ERR "sd_iostats_bump: nsect %d too big\n", nsect);
433 +               BUG();
434 +       }
435 +
436 +       counter = rq_data_dir(rq) == WRITE ?
437 +               &stats->iostat_write_histogram[bucket] :
438 +               &stats->iostat_read_histogram[bucket];
439 +
440 +       tmp = jiffies - rq->start_time;
441 +       for (tbucket = 0; tmp > 1; tbucket++)
442 +               tmp >>= 1;
443 +       if (tbucket >= IOSTAT_NCOUNTERS)
444 +               tbucket = IOSTAT_NCOUNTERS - 1;
445 +       //printk("%u ticks in Q to %u\n", jiffies - rq->start_time, tbucket);
446 +
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;
451 +
452 +       spin_lock_irqsave(&stats->iostat_lock, irqflags);
453 +
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++;
461 +
462 +       /* update delay stats */
463 +       if (rq_data_dir(rq) == WRITE) {
464 +               stats->iostat_wtime_in_queue[tbucket]++;
465 +               stats->iostat_write_reqs++;
466 +       } else {
467 +               stats->iostat_rtime_in_queue[tbucket]++;
468 +               stats->iostat_read_reqs++;
469 +       }
470 +
471 +       /* update size stats */
472 +       counter->iostat_size += nsect;
473 +       counter->iostat_count++;
474 +
475 +       stats->iostat_queue_stamp = jiffies;
476 +
477 +       spin_unlock_irqrestore(&stats->iostat_lock, irqflags);
478 +}
479 +#endif
480 +
481  /**
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);
487  
488 +#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
489 +       if (sdkp->stats) {
490 +               remove_proc_entry(disk->disk_name, sd_iostats_procdir);
491 +               kfree(sdkp->stats);
492 +               sdkp->stats = NULL;
493 +       }
494 +#endif
495         disk->private_data = NULL;
496         put_disk(disk);
497         put_device(&sdkp->device->sdev_gendev);
498 -
499         kfree(sdkp);
500  }
501  
502 @@ -2061,6 +2478,8 @@
503         if (!majors)
504                 return -ENODEV;
505  
506 +       sd_iostats_init();
507 +
508         err = class_register(&sd_disk_class);
509         if (err)
510                 goto err_out;
511 @@ -2076,6 +2495,7 @@
512  err_out:
513         for (i = 0; i < SD_MAJORS; i++)
514                 unregister_blkdev(sd_major(i), "sd");
515 +       sd_iostats_fini();
516         return err;
517  }
518  
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
523 @@ -37,6 +37,46 @@
524   */
525  #define SD_LAST_BUGGY_SECTORS  8
526  
527 +#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
528 +typedef struct {
529 +       unsigned long long iostat_size;
530 +       unsigned long long iostat_count;
531 +} iostat_counter_t;
532 +
533 +#define IOSTAT_NCOUNTERS 16
534 +typedef struct {
535 +       iostat_counter_t        iostat_read_histogram[IOSTAT_NCOUNTERS];
536 +       iostat_counter_t        iostat_write_histogram[IOSTAT_NCOUNTERS];
537 +       struct timeval          iostat_timeval;
538 +
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;
544 +
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;
553 +
554 +       /* process time: how long it takes to process requests */
555 +       unsigned long           iostat_rtime[IOSTAT_NCOUNTERS];
556 +       unsigned long           iostat_wtime[IOSTAT_NCOUNTERS];
557 +
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];
561 +
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;
565 +#endif
566 +
567  struct scsi_disk {
568         struct scsi_driver *driver;     /* always &sd_template */
569         struct scsi_device *device;
570 @@ -53,6 +93,9 @@
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 */
576 +#endif
577  };
578  #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev)
579