Whamcloud - gitweb
Branch HEAD
[fs/lustre-release.git] / lustre / kernel_patches / patches / sd_iostats-2.6-rhel4.patch
1 Index: linux-2.6.9-67.0.20/drivers/scsi/Kconfig
2 ===================================================================
3 --- linux-2.6.9-67.0.20.orig/drivers/scsi/Kconfig
4 +++ linux-2.6.9-67.0.20/drivers/scsi/Kconfig
5 @@ -61,6 +61,14 @@ config SCSI_DUMP
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-67.0.20/drivers/scsi/scsi_proc.c
21 ===================================================================
22 --- linux-2.6.9-67.0.20.orig/drivers/scsi/scsi_proc.c
23 +++ linux-2.6.9-67.0.20/drivers/scsi/scsi_proc.c
24 @@ -38,7 +38,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 DECLARE_MUTEX(global_host_template_sem);
34 Index: linux-2.6.9-67.0.20/drivers/scsi/sd.c
35 ===================================================================
36 --- linux-2.6.9-67.0.20.orig/drivers/scsi/sd.c
37 +++ linux-2.6.9-67.0.20/drivers/scsi/sd.c
38 @@ -63,6 +63,63 @@
39  
40  #include "scsi_logging.h"
41  
42 +#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
43 +# include <linux/proc_fs.h>
44 +# include <linux/seq_file.h>
45 +
46 +typedef struct {
47 +       unsigned long long iostat_size;
48 +       unsigned long long iostat_count;
49 +} iostat_counter_t;
50 +
51 +#define IOSTAT_NCOUNTERS 16
52 +typedef struct {
53 +       iostat_counter_t        iostat_read_histogram[IOSTAT_NCOUNTERS];
54 +       iostat_counter_t        iostat_write_histogram[IOSTAT_NCOUNTERS];
55 +       struct timeval          iostat_timeval;
56 +
57 +       /* queue depth: how well the pipe is filled up */
58 +       unsigned long long      iostat_queue_ticks[IOSTAT_NCOUNTERS];
59 +       unsigned long long      iostat_queue_ticks_sum;
60 +       unsigned long           iostat_queue_depth;
61 +       unsigned long           iostat_queue_stamp;
62 +
63 +       /* seeks: how linear the traffic is */
64 +       unsigned long long      iostat_next_sector;
65 +       unsigned long long      iostat_seek_sectors;
66 +       unsigned long long      iostat_seeks;
67 +       unsigned long long      iostat_sectors;
68 +       unsigned long long      iostat_reqs;
69 +       unsigned long           iostat_read_reqs;
70 +       unsigned long           iostat_write_reqs;
71 +
72 +       /* process time: how long it takes to process requests */
73 +       unsigned long           iostat_rtime[IOSTAT_NCOUNTERS];
74 +       unsigned long           iostat_wtime[IOSTAT_NCOUNTERS];
75 +
76 +       /* queue time: how long process spent in elevator's queue */
77 +       unsigned long           iostat_rtime_in_queue[IOSTAT_NCOUNTERS];
78 +       unsigned long           iostat_wtime_in_queue[IOSTAT_NCOUNTERS];
79 +
80 +       /* must be the last field, as it's used to know size to be memset'ed */
81 +       spinlock_t              iostat_lock;
82 +} ____cacheline_aligned_in_smp iostat_stats_t;
83 +
84 +struct proc_dir_entry *sd_iostats_procdir = NULL;
85 +char sd_iostats_procdir_name[] = "sd_iostats";
86 +static struct file_operations sd_iostats_proc_fops;
87 +
88 +extern void sd_iostats_init(void);
89 +extern void sd_iostats_fini(void);
90 +void sd_iostats_start_req(struct scsi_cmnd *SCpnt);
91 +void sd_iostats_finish_req(struct scsi_cmnd *SCpnt);
92 +#else
93 +static inline void sd_iostats_init(void) {}
94 +static inline void sd_iostats_fini(void) {}
95 +static inline void sd_iostats_start_req(struct scsi_cmnd *SCpnt) {}
96 +static inline void sd_iostats_finish_req(struct scsi_cmnd *SCpnt) {}
97 +#endif
98 +
99  /*
100   * More than enough for everybody ;)  The huge number of majors
101   * is a leftover from 16bit dev_t days, we don't really need that
102 @@ -101,6 +158,9 @@ struct scsi_disk {
103         u8              write_prot;
104         unsigned        WCE : 1;        /* state of disk WCE bit */
105         unsigned        RCD : 1;        /* state of disk RCD bit, unused */
106 +#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
107 +       iostat_stats_t  *stats;         /* scsi disk statistics */
108 +#endif
109  };
110  
111  static DEFINE_IDR(sd_index_idr);
112 @@ -391,6 +451,8 @@ queue:
113         SCpnt->allowed = SD_MAX_RETRIES;
114         SCpnt->timeout_per_command = timeout;
115  
116 +       sd_iostats_start_req(SCpnt);
117 +
118         /*
119          * This is the completion routine we use.  This is matched in terms
120          * of capability to this function.
121 @@ -849,6 +911,9 @@ static void sd_rw_intr(struct scsi_cmnd 
122                         break;
123                 }
124         }
125 +
126 +       sd_iostats_finish_req(SCpnt);
127 +
128         /*
129          * This calls the generic completion function, now that we know
130          * how many actual sectors finished, and how many sectors we need
131 @@ -1487,6 +1552,36 @@ static int sd_probe(struct device *dev)
132                 gd->flags |= GENHD_FL_REMOVABLE;
133         gd->queue = sdkp->device->request_queue;
134  
135 +#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
136 +       sdkp->stats = kzalloc(sizeof(iostat_stats_t), GFP_KERNEL);
137 +       if (!sdkp->stats) {
138 +               printk(KERN_WARNING "cannot allocate iostat structure for"
139 +                                   "%s\n", gd->disk_name);
140 +       } else {
141 +               do_gettimeofday(&sdkp->stats->iostat_timeval);
142 +               sdkp->stats->iostat_queue_stamp = jiffies;
143 +               spin_lock_init(&sdkp->stats->iostat_lock);
144 +               if (sd_iostats_procdir) {
145 +                       struct proc_dir_entry *pde;
146 +                       pde = create_proc_entry(gd->disk_name, S_IRUGO | S_IWUSR,
147 +                                               sd_iostats_procdir);
148 +                       if (!pde) {
149 +                               printk(KERN_WARNING "Can't create /proc/scsi/"
150 +                                                   "%s/%s\n",
151 +                                                   sd_iostats_procdir_name,
152 +                                                   gd->disk_name);
153 +                               kfree(sdkp->stats);
154 +                               sdkp->stats = NULL;
155 +                       } else {
156 +                               pde->proc_fops = &sd_iostats_proc_fops;
157 +                               pde->data = gd;
158 +                       }
159 +               } else {
160 +                       kfree(sdkp->stats);
161 +                       sdkp->stats = NULL;
162 +               }
163 +       }
164 +#endif
165         dev_set_drvdata(dev, sdkp);
166         add_disk(gd);
167  
168 @@ -1549,8 +1644,14 @@ static void scsi_disk_release(struct kre
169  
170         disk->private_data = NULL;
171  
172 +#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
173 +       if (sdkp->stats) {
174 +               remove_proc_entry(disk->disk_name, sd_iostats_procdir);
175 +               kfree(sdkp->stats);
176 +               sdkp->stats = NULL;
177 +       }
178 +#endif
179         put_disk(disk);
180 -
181         kfree(sdkp);
182  }
183  
184 @@ -1575,6 +1676,366 @@ static void sd_shutdown(struct device *d
185         sd_sync_cache(sdp);
186  }      
187  
188 +#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
189 +static int
190 +sd_iostats_seq_show(struct seq_file *seq, void *v)
191 +{
192 +       struct timeval     now;
193 +       struct gendisk *disk = seq->private;
194 +       iostat_stats_t    *stats;
195 +       unsigned long long read_len;
196 +       unsigned long long read_len_tot;
197 +       unsigned long      read_num;
198 +       unsigned long      read_num_tot;
199 +       unsigned long long write_len;
200 +       unsigned long long write_len_tot;
201 +       unsigned long      write_num;
202 +       unsigned long      write_num_tot;
203 +       int                i;
204 +       int                maxi;
205 +
206 +       stats = scsi_disk(disk)->stats;
207 +       if (stats == NULL) {
208 +               printk(KERN_ERR "sd_iostats_seq_show: NULL stats entry\n");
209 +               BUG();
210 +       }
211 +
212 +       do_gettimeofday(&now);
213 +       now.tv_sec -= stats->iostat_timeval.tv_sec;
214 +       now.tv_usec -= stats->iostat_timeval.tv_usec;
215 +       if (now.tv_usec < 0) {
216 +               now.tv_usec += 1000000;
217 +               now.tv_sec--;
218 +       }
219 +
220 +       /* this sampling races with updates */
221 +       seq_printf(seq, "index:        %lu   snapshot_time:         %lu.%06lu\n",
222 +                       (unsigned long) scsi_disk(disk)->index,
223 +                       now.tv_sec, now.tv_usec);
224 +
225 +       for (i = IOSTAT_NCOUNTERS - 1; i > 0; i--)
226 +               if (stats->iostat_read_histogram[i].iostat_count != 0 ||
227 +                               stats->iostat_write_histogram[i].iostat_count != 0)
228 +                       break;
229 +       maxi = i;
230 +
231 +       seq_printf(seq, "%8s %8s %12s %8s %12s\n", "size", 
232 +                       "reads", "total", "writes", "total");
233 +
234 +       read_len_tot = write_len_tot = 0;
235 +       read_num_tot = write_num_tot = 0;
236 +       for (i = 0; i <= maxi; i++) {
237 +               read_len = stats->iostat_read_histogram[i].iostat_size;
238 +               read_len_tot += read_len;
239 +               read_num = stats->iostat_read_histogram[i].iostat_count;
240 +               read_num_tot += read_num;
241 +
242 +               write_len = stats->iostat_write_histogram[i].iostat_size;
243 +               write_len_tot += write_len;
244 +               write_num = stats->iostat_write_histogram[i].iostat_count;
245 +               write_num_tot += write_num;
246 +
247 +               seq_printf (seq, "%8d %8lu %12llu %8lu %12llu\n", 
248 +                               512<<i, read_num, read_len, write_num, write_len);
249 +       }
250 +
251 +       seq_printf(seq, "%8s %8lu %12llu %8lu %12llu\n\n", "total",
252 +                       read_num_tot, read_len_tot, 
253 +                       write_num_tot, write_len_tot);
254 +
255 +       seq_printf(seq, "%8s %8s %8s\n", "qdepth", "ticks", "%");
256 +       for (i = 0; i < IOSTAT_NCOUNTERS; i++) {
257 +               unsigned long long ticks, percent;
258 +               ticks = stats->iostat_queue_ticks[i];
259 +               if (ticks == 0)
260 +                       continue;
261 +               percent = stats->iostat_queue_ticks[i] * 100;
262 +               do_div(percent, stats->iostat_queue_ticks_sum);
263 +               seq_printf(seq, "%8d %8llu %8llu\n", i, ticks, percent);
264 +       }
265 +
266 +       if (stats->iostat_reqs != 0) {
267 +               unsigned long long aveseek = 0, percent = 0;
268 +
269 +               if (stats->iostat_seeks) {
270 +                       aveseek = stats->iostat_seek_sectors;
271 +                       do_div(aveseek, stats->iostat_seeks);
272 +                       percent = stats->iostat_seeks * 100;
273 +                       do_div(percent, stats->iostat_reqs);
274 +               }
275 +
276 +               seq_printf(seq, "\n%llu sectors in %llu reqs: %llu seek(s) over "
277 +                               "%llu sectors in ave, %llu%% of all reqs\n",
278 +                               stats->iostat_sectors, stats->iostat_reqs,
279 +                               stats->iostat_seeks, aveseek, percent);
280 +       }
281 +
282 +       seq_printf(seq, "\n%16s %8s %8s %8s %8s\n", "process time", "reads",
283 +                       "%%", "writes", "%%");
284 +       for (i = 0; i < IOSTAT_NCOUNTERS; i++) {
285 +               unsigned long read_percent = 0, write_percent = 0;
286 +               if (stats->iostat_wtime[i] == 0 &&
287 +                               stats->iostat_rtime[i] == 0)
288 +                       continue;
289 +               if (stats->iostat_read_reqs)
290 +                       read_percent = stats->iostat_rtime[i] * 100 / 
291 +                               stats->iostat_read_reqs;
292 +               if (stats->iostat_write_reqs)
293 +                       write_percent = stats->iostat_wtime[i] * 100 / 
294 +                               stats->iostat_write_reqs;
295 +               seq_printf(seq, "%16u %8lu %8lu %8lu %8lu\n",
296 +                               jiffies_to_msecs(((1UL << i) >> 1) << 1),
297 +                               stats->iostat_rtime[i], read_percent,
298 +                               stats->iostat_wtime[i], write_percent);
299 +       }
300 +
301 +       seq_printf(seq, "\n%16s %8s %8s %8s %8s\n", "time in queue", "reads",
302 +                       "%%", "writes", "%%");
303 +       for (i = 0; i < IOSTAT_NCOUNTERS; i++) {
304 +               unsigned long read_percent = 0, write_percent = 0;
305 +               if (stats->iostat_wtime_in_queue[i] == 0 &&
306 +                               stats->iostat_rtime_in_queue[i] == 0)
307 +                       continue;
308 +               if (stats->iostat_read_reqs)
309 +                       read_percent = stats->iostat_rtime_in_queue[i] * 100 / 
310 +                               stats->iostat_read_reqs;
311 +               if (stats->iostat_write_reqs)
312 +                       write_percent = stats->iostat_wtime_in_queue[i] * 100 / 
313 +                               stats->iostat_write_reqs;
314 +               seq_printf(seq, "%16u %8lu %8lu %8lu %8lu\n",
315 +                               jiffies_to_msecs(((1UL << i) >> 1) << 1),
316 +                               stats->iostat_rtime_in_queue[i],
317 +                               read_percent,
318 +                               stats->iostat_wtime_in_queue[i],
319 +                               write_percent);
320 +       }
321 +
322 +       return 0;
323 +}
324 +
325 +static void *
326 +sd_iostats_seq_start(struct seq_file *p, loff_t *pos)
327 +{
328 +       return (*pos == 0) ? (void *)1 : NULL;
329 +}
330 +
331 +static void *
332 +sd_iostats_seq_next(struct seq_file *p, void *v, loff_t *pos)
333 +{
334 +       ++*pos;
335 +       return NULL;
336 +}
337 +
338 +static void
339 +sd_iostats_seq_stop(struct seq_file *p, void *v)
340 +{
341 +}
342 +
343 +static struct seq_operations sd_iostats_seqops = {
344 +       .start = sd_iostats_seq_start,
345 +       .stop  = sd_iostats_seq_stop,
346 +       .next  = sd_iostats_seq_next,
347 +       .show  = sd_iostats_seq_show,
348 +};
349 +
350 +static int
351 +sd_iostats_seq_open (struct inode *inode, struct file *file)
352 +{
353 +       int rc;
354 +
355 +       rc = seq_open(file, &sd_iostats_seqops);
356 +       if (rc != 0)
357 +               return rc;
358 +
359 +       ((struct seq_file *)file->private_data)->private = PDE(inode)->data;
360 +       return 0;
361 +}
362 +
363 +static ssize_t
364 +sd_iostats_seq_write(struct file *file, const char *buffer,
365 +                    size_t len, loff_t *off)
366 +{
367 +       struct seq_file   *seq = file->private_data;
368 +       struct gendisk *disk = seq->private;
369 +       iostat_stats_t    *stats = scsi_disk(disk)->stats;
370 +       unsigned long      flags;
371 +       unsigned long      qdepth;
372 +
373 +
374 +       spin_lock_irqsave (&stats->iostat_lock, flags);
375 +       qdepth = stats->iostat_queue_depth;
376 +       memset (stats, 0, offsetof(iostat_stats_t, iostat_lock));
377 +       do_gettimeofday(&stats->iostat_timeval);
378 +       stats->iostat_queue_stamp = jiffies;
379 +       stats->iostat_queue_depth = qdepth;
380 +       spin_unlock_irqrestore (&stats->iostat_lock, flags);
381 +
382 +       return len;
383 +}
384 +
385 +static struct file_operations sd_iostats_proc_fops = {
386 +       .owner   = THIS_MODULE,
387 +       .open    = sd_iostats_seq_open,
388 +       .read    = seq_read,
389 +       .write   = sd_iostats_seq_write,
390 +       .llseek  = seq_lseek,
391 +       .release = seq_release,
392 +};
393 +
394 +extern struct proc_dir_entry *proc_scsi;
395 +
396 +void
397 +sd_iostats_init(void)
398 +{
399 +       if (proc_scsi == NULL) {
400 +               printk(KERN_WARNING "No access to sd iostats: "
401 +                       "proc_scsi is NULL\n");
402 +               return;
403 +       }
404 +
405 +       sd_iostats_procdir = create_proc_entry(sd_iostats_procdir_name,
406 +                       S_IFDIR | S_IRUGO | S_IXUGO,
407 +                       proc_scsi);
408 +       if (sd_iostats_procdir == NULL) {
409 +               printk(KERN_WARNING "No access to sd iostats: "
410 +                       "can't create /proc/scsi/%s\n", sd_iostats_procdir_name);
411 +               return;
412 +       }
413 +}
414 +
415 +void sd_iostats_fini(void)
416 +{
417 +       if (proc_scsi != NULL && sd_iostats_procdir != NULL)
418 +               remove_proc_entry(sd_iostats_procdir_name, proc_scsi);
419 +
420 +       sd_iostats_procdir = NULL;
421 +}
422 +
423 +void sd_iostats_finish_req(struct scsi_cmnd *SCpnt)
424 +{
425 +       struct request          *rq = SCpnt->request;
426 +       iostat_stats_t          *stats;
427 +       unsigned long           *tcounter;
428 +       int                     tbucket;
429 +       int                     tmp;
430 +       unsigned long           irqflags;
431 +       unsigned long           i;
432 +
433 +       stats = scsi_disk(rq->rq_disk)->stats;
434 +       if (stats == NULL)
435 +               return;
436 +
437 +       tmp = jiffies -  rq->start_time;
438 +       for (tbucket = 0; tmp > 1; tbucket++)
439 +               tmp >>= 1;
440 +       if (tbucket >= IOSTAT_NCOUNTERS)
441 +               tbucket = IOSTAT_NCOUNTERS - 1;
442 +       //printk("%u ticks in D to %u\n", jiffies - rq->start_time, tbucket);
443 +
444 +       tcounter = rq_data_dir(rq) == WRITE ? 
445 +               &stats->iostat_wtime[tbucket] : &stats->iostat_rtime[tbucket];
446 +
447 +       spin_lock_irqsave(&stats->iostat_lock, irqflags);
448 +
449 +       /* update delay stats */
450 +       (*tcounter)++;
451 +
452 +       /* update queue depth stats */
453 +       i = stats->iostat_queue_depth;
454 +       if (i >= IOSTAT_NCOUNTERS)
455 +               i = IOSTAT_NCOUNTERS - 1;
456 +       stats->iostat_queue_ticks[i] += jiffies - stats->iostat_queue_stamp;
457 +       stats->iostat_queue_ticks_sum += jiffies - stats->iostat_queue_stamp;
458 +       BUG_ON(stats->iostat_queue_depth == 0);
459 +       stats->iostat_queue_depth--;
460 +
461 +       /* update seek stats. XXX: not sure about nr_sectors */
462 +       stats->iostat_sectors += rq->nr_sectors;
463 +       stats->iostat_reqs++;
464 +       if (rq->sector != stats->iostat_next_sector) {
465 +               stats->iostat_seek_sectors += 
466 +                       rq->sector > stats->iostat_next_sector ?
467 +                       rq->sector - stats->iostat_next_sector :
468 +                       stats->iostat_next_sector - rq->sector;
469 +               stats->iostat_seeks++;
470 +       }
471 +       stats->iostat_next_sector = rq->sector + rq->nr_sectors;
472 +
473 +       stats->iostat_queue_stamp = jiffies;
474 +
475 +       spin_unlock_irqrestore(&stats->iostat_lock, irqflags);
476 +}
477 +
478 +void sd_iostats_start_req(struct scsi_cmnd *SCpnt)
479 +{
480 +       struct request          *rq = SCpnt->request;
481 +       iostat_stats_t          *stats;
482 +       iostat_counter_t        *counter;
483 +       int                     bucket;
484 +       int                     tbucket;
485 +       int                     tmp;
486 +       unsigned long           irqflags;
487 +       unsigned long           i;
488 +       int                     nsect;
489 +
490 +       stats = scsi_disk(rq->rq_disk)->stats;
491 +       if (stats == NULL)
492 +               return;
493 +
494 +       nsect = SCpnt->request_bufflen >> 9;
495 +       for (bucket = 0, tmp = nsect; tmp > 1; bucket++)
496 +               tmp >>= 1;
497 +
498 +       if (bucket >= IOSTAT_NCOUNTERS) {
499 +               printk (KERN_ERR "sd_iostats_bump: nsect %d too big\n", nsect);
500 +               BUG();
501 +       }
502 +
503 +       counter = rq_data_dir(rq) == WRITE ? 
504 +               &stats->iostat_write_histogram[bucket] :
505 +               &stats->iostat_read_histogram[bucket];
506 +
507 +       tmp = jiffies - rq->start_time;
508 +       for (tbucket = 0; tmp > 1; tbucket++)
509 +               tmp >>= 1;
510 +       if (tbucket >= IOSTAT_NCOUNTERS)
511 +               tbucket = IOSTAT_NCOUNTERS - 1;
512 +       //printk("%u ticks in Q to %u\n", jiffies - rq->start_time, tbucket);
513 +
514 +       /* an ugly hack to know exact processing time. the right
515 +        * solution is to add one more field to struct request
516 +        * hopefully it will break nothing ... */
517 +       rq->start_time = jiffies;
518 +
519 +       spin_lock_irqsave(&stats->iostat_lock, irqflags);
520 +
521 +       /* update queue depth stats */
522 +       i = stats->iostat_queue_depth;
523 +       if (i >= IOSTAT_NCOUNTERS)
524 +               i = IOSTAT_NCOUNTERS - 1;
525 +       stats->iostat_queue_ticks[i] += jiffies - stats->iostat_queue_stamp;
526 +       stats->iostat_queue_ticks_sum += jiffies - stats->iostat_queue_stamp;
527 +       stats->iostat_queue_depth++;
528 +
529 +       /* update delay stats */
530 +       if (rq_data_dir(rq) == WRITE) {
531 +               stats->iostat_wtime_in_queue[tbucket]++;
532 +               stats->iostat_write_reqs++;
533 +       } else {
534 +               stats->iostat_rtime_in_queue[tbucket]++;
535 +               stats->iostat_read_reqs++;
536 +       }
537 +
538 +       /* update size stats */
539 +       counter->iostat_size += nsect;
540 +       counter->iostat_count++;
541 +
542 +       stats->iostat_queue_stamp = jiffies;
543 +
544 +       spin_unlock_irqrestore(&stats->iostat_lock, irqflags);
545 +}
546 +#endif
547 +
548  /**
549   *     init_sd - entry point for this driver (both when built in or when
550   *     a module).
551 @@ -1584,6 +2045,7 @@ static void sd_shutdown(struct device *d
552  static int __init init_sd(void)
553  {
554         int majors = 0, i;
555 +       int rc = 0;
556  
557         SCSI_LOG_HLQUEUE(3, printk("init_sd: sd driver entry point\n"));
558  
559 @@ -1594,7 +2056,11 @@ static int __init init_sd(void)
560         if (!majors)
561                 return -ENODEV;
562  
563 -       return scsi_register_driver(&sd_template.gendrv);
564 +       sd_iostats_init();
565 +       rc = scsi_register_driver(&sd_template.gendrv);
566 +       if (rc)
567 +               sd_iostats_fini();
568 +       return rc;
569  }
570  
571  /**
572 @@ -1611,6 +2077,7 @@ static void __exit exit_sd(void)
573         scsi_unregister_driver(&sd_template.gendrv);
574         for (i = 0; i < SD_MAJORS; i++)
575                 unregister_blkdev(sd_major(i), "sd");
576 +       sd_iostats_fini();
577  }
578  
579  MODULE_LICENSE("GPL");