]> git.pld-linux.org Git - packages/kernel.git/blame - kernel-sd_iostats-2.6.22.patch
- fix netlink (inet_diag) inside vservers
[packages/kernel.git] / kernel-sd_iostats-2.6.22.patch
CommitLineData
c80d6cf3 1Index: linux-2.6.22-rc4/drivers/scsi/Kconfig
2===================================================================
3--- linux-2.6.22-rc4.orig/drivers/scsi/Kconfig 2007-06-11 20:23:32.000000000 +0200
4+++ linux-2.6.22-rc4/drivers/scsi/Kconfig 2007-06-11 20:24:20.000000000 +0200
5@@ -75,6 +75,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
20Index: linux-2.6.22-rc4/drivers/scsi/sd.c
21===================================================================
22--- linux-2.6.22-rc4.orig/drivers/scsi/sd.c 2007-06-11 20:23:32.000000000 +0200
23+++ linux-2.6.22-rc4/drivers/scsi/sd.c 2007-06-11 20:33:35.000000000 +0200
24@@ -244,6 +244,38 @@
25 .issue_flush = sd_issue_flush,
26 };
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 * Device no to disk mapping:
62 *
63@@ -347,6 +379,9 @@
64 (unsigned long long)block,
65 this_count));
66
67+ sd_iostats_bump(scsi_disk(disk)->index, this_count,
68+ rq_data_dir(SCpnt->request) == WRITE);
69+
70 if (!sdp || !scsi_device_online(sdp) ||
71 block + rq->nr_sectors > get_capacity(disk)) {
72 SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt,
73@@ -575,6 +610,8 @@
74 scsi_set_medium_removal(sdev, SCSI_REMOVAL_PREVENT);
75 }
76
77+ sd_iostats_init_disk(disk);
78+
79 return 0;
80
81 error_out:
82@@ -1002,6 +1039,7 @@
83 return 1;
84 }
85
86+#define SD_STATS 256
87 /*
88 * spinup disk - called only in sd_revalidate_disk()
89 */
90@@ -1684,6 +1722,327 @@
91 return error;
92 }
93
94+#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))
95+static int
96+sd_iostats_seq_show(struct seq_file *seq, void *v)
97+{
98+ struct timeval now;
99+ struct gendisk *disk = seq->private;
100+ iostat_stats_t *stats;
101+ unsigned long long read_len;
102+ unsigned long long read_len_tot;
103+ unsigned long read_num;
104+ unsigned long read_num_tot;
105+ unsigned long long write_len;
106+ unsigned long long write_len_tot;
107+ unsigned long write_num;
108+ unsigned long write_num_tot;
109+ int i;
110+ int maxi;
111+
112+ if (sd_iostats == NULL) {
113+ printk(KERN_ERR "sd_iostats_seq_show: NULL stats array\n");
114+ BUG();
115+ }
116+
117+ stats = sd_iostats[scsi_disk(disk)->index];
118+ if (stats == NULL) {
119+ printk(KERN_ERR "sd_iostats_seq_show: NULL stats entry\n");
120+ BUG();
121+ }
122+
123+ do_gettimeofday(&now);
124+ now.tv_sec -= stats->iostat_timeval.tv_sec;
125+ now.tv_usec -= stats->iostat_timeval.tv_usec;
126+ if (now.tv_usec < 0) {
127+ now.tv_usec += 1000000;
128+ now.tv_sec--;
129+ }
130+
131+ /* this sampling races with updates */
132+ seq_printf(seq, "index: %u snapshot_time: %lu.%06lu\n",
133+ scsi_disk(disk)->index, now.tv_sec, now.tv_usec);
134+
135+ for (i = IOSTAT_NCOUNTERS - 1; i > 0; i--)
136+ if (stats->iostat_read_histogram[i].iostat_count != 0 ||
137+ stats->iostat_write_histogram[i].iostat_count != 0)
138+ break;
139+ maxi = i;
140+
141+ seq_printf(seq, "%8s %8s %12s %8s %12s\n", "size",
142+ "reads", "total", "writes", "total");
143+
144+ read_len_tot = write_len_tot = 0;
145+ read_num_tot = write_num_tot = 0;
146+ for (i = 0; i <= maxi; i++) {
147+ read_len = stats->iostat_read_histogram[i].iostat_size;
148+ read_len_tot += read_len;
149+ read_num = stats->iostat_read_histogram[i].iostat_count;
150+ read_num_tot += read_num;
151+
152+ write_len = stats->iostat_write_histogram[i].iostat_size;
153+ write_len_tot += write_len;
154+ write_num = stats->iostat_write_histogram[i].iostat_count;
155+ write_num_tot += write_num;
156+
157+ seq_printf (seq, "%8d %8lu %12llu %8lu %12llu\n",
158+ 512<<i, read_num, read_len, write_num, write_len);
159+ }
160+
161+ seq_printf(seq, "%8s %8lu %12llu %8lu %12llu\n", "total",
162+ read_num_tot, read_len_tot,
163+ write_num_tot, write_len_tot);
164+ return 0;
165+}
166+
167+static void *
168+sd_iostats_seq_start(struct seq_file *p, loff_t *pos)
169+{
170+ return (*pos == 0) ? (void *)1 : NULL;
171+}
172+
173+static void *
174+sd_iostats_seq_next(struct seq_file *p, void *v, loff_t *pos)
175+{
176+ ++*pos;
177+ return NULL;
178+}
179+
180+static void
181+sd_iostats_seq_stop(struct seq_file *p, void *v)
182+{
183+}
184+
185+static struct seq_operations sd_iostats_seqops = {
186+ .start = sd_iostats_seq_start,
187+ .stop = sd_iostats_seq_stop,
188+ .next = sd_iostats_seq_next,
189+ .show = sd_iostats_seq_show,
190+};
191+
192+static int
193+sd_iostats_seq_open (struct inode *inode, struct file *file)
194+{
195+ int rc;
196+
197+ rc = seq_open(file, &sd_iostats_seqops);
198+ if (rc != 0)
199+ return rc;
200+
201+ ((struct seq_file *)file->private_data)->private = PDE(inode)->data;
202+ return 0;
203+}
204+
205+static ssize_t
206+sd_iostats_seq_write(struct file *file, const char *buffer,
207+ size_t len, loff_t *off)
208+{
209+ struct seq_file *seq = file->private_data;
210+ struct gendisk *disk = seq->private;
211+ iostat_stats_t *stats = sd_iostats[scsi_disk(disk)->index];
212+ unsigned long flags;
213+
214+
215+ spin_lock_irqsave (&sd_iostats_lock, flags);
216+ memset (stats, 0, sizeof(*stats));
217+ do_gettimeofday(&stats->iostat_timeval);
218+ spin_unlock_irqrestore (&sd_iostats_lock, flags);
219+
220+ return len;
221+}
222+
223+static struct file_operations sd_iostats_proc_fops = {
224+ .owner = THIS_MODULE,
225+ .open = sd_iostats_seq_open,
226+ .read = seq_read,
227+ .write = sd_iostats_seq_write,
228+ .llseek = seq_lseek,
229+ .release = seq_release,
230+};
231+
232+extern struct proc_dir_entry *proc_scsi;
233+
234+void
235+sd_iostats_init(void)
236+{
237+ int i;
238+
239+ spin_lock_init(&sd_iostats_lock);
240+
241+ sd_iostats = kmalloc(SD_STATS * sizeof(iostat_stats_t *), GFP_KERNEL);
242+ if (sd_iostats == NULL) {
243+ printk(KERN_WARNING "Can't keep sd iostats: "
244+ "ENOMEM allocating stats array size %ld\n",
245+ SD_STATS * sizeof(iostat_stats_t *));
246+ return;
247+ }
248+
249+ for (i = 0; i < SD_STATS; i++)
250+ sd_iostats[i] = NULL;
251+
252+ if (proc_scsi == NULL) {
253+ printk(KERN_WARNING "No access to sd iostats: "
254+ "proc_scsi is NULL\n");
255+ return;
256+ }
257+
258+ sd_iostats_procdir = create_proc_entry(sd_iostats_procdir_name,
259+ S_IFDIR | S_IRUGO | S_IXUGO,
260+ proc_scsi);
261+ if (sd_iostats_procdir == NULL) {
262+ printk(KERN_WARNING "No access to sd iostats: "
263+ "can't create /proc/scsi/%s\n", sd_iostats_procdir_name);
264+ return;
265+ }
266+}
267+
268+void
269+sd_iostats_init_disk(struct gendisk *disk)
270+{
271+ struct proc_dir_entry *pde;
272+ unsigned long flags;
273+ iostat_stats_t *stats;
274+
275+ if (sd_iostats == NULL ||
276+ sd_iostats_procdir == NULL)
277+ return;
278+
279+ if (scsi_disk(disk)->index > SD_STATS) {
280+ printk(KERN_ERR "sd_iostats_init_disk: "
281+ "unexpected disk index %d(%d)\n",
282+ scsi_disk(disk)->index, SD_STATS);
283+ return;
284+ }
285+
286+ if (sd_iostats[scsi_disk(disk)->index] != NULL)
287+ return;
288+
289+ stats = kmalloc(sizeof(*stats), GFP_KERNEL);
290+ if (stats == NULL) {
291+ printk(KERN_WARNING "Can't keep %s iostats: "
292+ "ENOMEM allocating stats size %ld\n",
293+ disk->disk_name, sizeof(*stats));
294+ return;
295+ }
296+
297+ memset (stats, 0, sizeof(*stats));
298+ do_gettimeofday(&stats->iostat_timeval);
299+
300+ spin_lock_irqsave(&sd_iostats_lock, flags);
301+
302+ if (sd_iostats[scsi_disk(disk)->index] != NULL) {
303+ spin_unlock_irqrestore(&sd_iostats_lock, flags);
304+ kfree (stats);
305+ return;
306+ }
307+
308+ sd_iostats[scsi_disk(disk)->index] = stats;
309+
310+ spin_unlock_irqrestore(&sd_iostats_lock, flags);
311+
312+ pde = create_proc_entry(disk->disk_name, S_IRUGO | S_IWUSR,
313+ sd_iostats_procdir);
314+ if (pde == NULL) {
315+ printk(KERN_WARNING "Can't create /proc/scsi/%s/%s\n",
316+ sd_iostats_procdir_name, disk->disk_name);
317+ } else {
318+ pde->proc_fops = &sd_iostats_proc_fops;
319+ pde->data = disk;
320+ }
321+}
322+
323+static void sd_devname(unsigned int disknum, char *buffer)
324+{
325+ if (disknum < 26)
326+ sprintf(buffer, "sd%c", 'a' + disknum);
327+ else {
328+ unsigned int min1;
329+ unsigned int min2;
330+ /*
331+ * For larger numbers of disks, we need to go to a new
332+ * naming scheme.
333+ */
334+ min1 = disknum / 26;
335+ min2 = disknum % 26;
336+ sprintf(buffer, "sd%c%c", 'a' + min1 - 1, 'a' + min2);
337+ }
338+}
339+
340+void
341+sd_iostats_fini(void)
342+{
343+ char name[6];
344+ int i;
345+
346+ if (sd_iostats_procdir != NULL) {
347+ for (i = 0; i < SD_STATS; i++) {
348+ sd_devname(i, name);
349+ remove_proc_entry(name, sd_iostats_procdir);
350+ }
351+
352+ if (proc_scsi == NULL) {
353+ printk(KERN_ERR "sd_iostats_fini: proc_scsi NULL\n");
354+ BUG();
355+ }
356+ remove_proc_entry(sd_iostats_procdir_name,
357+ proc_scsi);
358+
359+ sd_iostats_procdir = NULL;
360+ }
361+
362+ if (sd_iostats != NULL) {
363+ for (i = 0; i < SD_STATS; i++) {
364+ if (sd_iostats[i] != NULL)
365+ kfree (sd_iostats[i]);
366+ }
367+
368+ kfree(sd_iostats);
369+ sd_iostats = NULL;
370+ }
371+}
372+
373+void
374+sd_iostats_bump(int disk, unsigned int nsect, int iswrite)
375+{
376+ iostat_stats_t *stats;
377+ iostat_counter_t *counter;
378+ int bucket;
379+ int tmp;
380+ unsigned long irqflags;
381+
382+ if (sd_iostats == NULL)
383+ return;
384+
385+ if (disk < 0 || disk >= SD_STATS) {
386+ printk(KERN_ERR "sd_iostats_bump: unexpected disk index %d([0-%d])\n",
387+ disk, SD_STATS);
388+ BUG();
389+ }
390+
391+ for (bucket = 0, tmp = nsect; tmp > 1; bucket++)
392+ tmp /= 2;
393+
394+ if (bucket >= IOSTAT_NCOUNTERS) {
395+ printk (KERN_ERR "sd_iostats_bump: nsect %d too big\n", nsect);
396+ BUG();
397+ }
398+
399+ spin_lock_irqsave(&sd_iostats_lock, irqflags);
400+
401+ stats = sd_iostats[disk];
402+ if (stats != NULL) {
403+ counter = iswrite ?
404+ &stats->iostat_write_histogram[bucket] :
405+ &stats->iostat_read_histogram[bucket];
406+
407+ counter->iostat_size += nsect;
408+ counter->iostat_count++;
409+ }
410+
411+ spin_unlock_irqrestore(&sd_iostats_lock, irqflags);
412+}
413+#endif
414+
415 /**
416 * sd_remove - called whenever a scsi disk (previously recognized by
417 * sd_probe) is detached from the system. It is called (potentially
418@@ -1855,6 +2214,7 @@
419 if (err)
420 goto err_out_class;
421
422+ sd_iostats_init();
423 return 0;
424
425 err_out_class:
426@@ -1876,6 +2236,7 @@
427
428 SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n"));
429
430+ sd_iostats_fini();
431 scsi_unregister_driver(&sd_template.gendrv);
432 class_unregister(&sd_disk_class);
433
434Index: linux-2.6.22-rc4/drivers/scsi/scsi_proc.c
435===================================================================
436--- linux-2.6.22-rc4.orig/drivers/scsi/scsi_proc.c 2007-06-11 20:23:32.000000000 +0200
437+++ linux-2.6.22-rc4/drivers/scsi/scsi_proc.c 2007-06-11 20:24:20.000000000 +0200
438@@ -40,7 +40,8 @@
439 /* 4K page size, but our output routines, use some slack for overruns */
440 #define PROC_BLOCK_SIZE (3*1024)
441
442-static struct proc_dir_entry *proc_scsi;
443+struct proc_dir_entry *proc_scsi;
444+EXPORT_SYMBOL(proc_scsi);
445
446 /* Protect sht->present and sht->proc_dir */
447 static DEFINE_MUTEX(global_host_template_mutex);
This page took 0.074781 seconds and 4 git commands to generate.