📄 sd_iostats-2.6-rhel5.patch
字号:
Index: linux-2.6.9-5.0.3.EL/drivers/scsi/Kconfig
===================================================================
Index: linux-2.6.9/drivers/scsi/Kconfig===================================================================--- linux-2.6.9.orig/drivers/scsi/Kconfig 2007-07-23 14:19:13.000000000 +0400+++ linux-2.6.9/drivers/scsi/Kconfig 2007-07-26 14:16:36.000000000 +0400@@ -61,6 +61,14 @@ config SCSI_DUMP help SCSI dump support +config SD_IOSTATS+ bool "Enable SCSI disk I/O stats"+ depends on BLK_DEV_SD+ default y+ ---help---+ This enables SCSI disk I/O stats collection. You must also enable+ /proc file system support if you want this feature.+ config CHR_DEV_ST tristate "SCSI tape support" depends on SCSIIndex: linux-2.6.9/drivers/scsi/scsi_proc.c===================================================================--- linux-2.6.9.orig/drivers/scsi/scsi_proc.c 2007-03-13 02:47:28.000000000 +0300+++ linux-2.6.9/drivers/scsi/scsi_proc.c 2007-07-26 14:16:36.000000000 +0400@@ -38,7 +38,8 @@ /* 4K page size, but our output routines, use some slack for overruns */ #define PROC_BLOCK_SIZE (3*1024) -static struct proc_dir_entry *proc_scsi;+struct proc_dir_entry *proc_scsi;+EXPORT_SYMBOL(proc_scsi); /* Protect sht->present and sht->proc_dir */ static DECLARE_MUTEX(global_host_template_sem);Index: linux-2.6.9/drivers/scsi/sd.c===================================================================--- linux-2.6.9.orig/drivers/scsi/sd.c 2007-03-13 02:47:27.000000000 +0300+++ linux-2.6.9/drivers/scsi/sd.c 2007-07-28 14:55:56.000000000 +0400@@ -63,6 +63,67 @@ #include "scsi_logging.h" +#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))+# include <linux/proc_fs.h>+# include <linux/seq_file.h>++typedef struct {+ unsigned long long iostat_size;+ unsigned long long iostat_count;+} iostat_counter_t;++#define IOSTAT_NCOUNTERS 16+typedef struct {+ iostat_counter_t iostat_read_histogram[IOSTAT_NCOUNTERS];+ iostat_counter_t iostat_write_histogram[IOSTAT_NCOUNTERS];+ struct timeval iostat_timeval;++ /* queue depth: how well the pipe is filled up */+ unsigned long long iostat_queue_ticks[IOSTAT_NCOUNTERS];+ unsigned long long iostat_queue_ticks_sum;+ unsigned long iostat_queue_depth;+ unsigned long iostat_queue_stamp;++ /* seeks: how linear the traffic is */+ unsigned long long iostat_next_sector;+ unsigned long long iostat_seek_sectors;+ unsigned long long iostat_seeks;+ unsigned long long iostat_sectors;+ unsigned long long iostat_reqs;+ unsigned long iostat_read_reqs;+ unsigned long iostat_write_reqs;++ /* process time: how long it takes to process requests */+ unsigned long iostat_rtime[IOSTAT_NCOUNTERS];+ unsigned long iostat_wtime[IOSTAT_NCOUNTERS];++ /* queue time: how long process spent in elevator's queue */+ unsigned long iostat_rtime_in_queue[IOSTAT_NCOUNTERS];+ unsigned long iostat_wtime_in_queue[IOSTAT_NCOUNTERS];++ char iostat_name[32];++ /* must be the last field, as it's used to know size to be memset'ed */+ spinlock_t iostat_lock;+} ____cacheline_aligned_in_smp iostat_stats_t;++iostat_stats_t **sd_iostats;+struct proc_dir_entry *sd_iostats_procdir;+char sd_iostats_procdir_name[] = "sd_iostats";++extern void sd_iostats_init(void);+extern void sd_iostats_init_disk(struct gendisk *);+extern void sd_iostats_fini(void);+void sd_iostats_start_req(struct scsi_cmnd *SCpnt);+void sd_iostats_finish_req(struct scsi_cmnd *SCpnt);+#else+static inline void sd_iostats_init(void) {}+static inline void sd_iostats_init_disk(struct gendisk *disk) {}+static inline void sd_iostats_fini(void) {}+static inline void sd_iostats_start_req(struct scsi_cmnd *SCpnt) {}+static inline void sd_iostats_finish_req(struct scsi_cmnd *SCpnt) {}+#endif+ /* * More than enough for everybody ;) The huge number of majors * is a leftover from 16bit dev_t days, we don't really need that@@ -76,6 +137,7 @@ */ #define SD_MAX_DISKS (((26 * 26) + 26 + 1) * 26) +#define SD_STATS 256 /* * Time out in seconds for disks and Magneto-opticals (which are slower). */@@ -278,6 +340,8 @@ static int sd_init_command(struct scsi_c SCSI_LOG_HLQUEUE(2, printk("%s : block=%llu\n", disk->disk_name, (unsigned long long)block)); + sd_iostats_start_req(SCpnt);+ /* * If we have a 1K hardware sectorsize, prevent access to single * 512 byte sectors. In theory we could handle this - in fact@@ -474,6 +538,7 @@ static int sd_open(struct inode *inode, scsi_set_medium_removal(sdev, SCSI_REMOVAL_PREVENT); } + sd_iostats_init_disk(disk); return 0; error_out:@@ -849,6 +914,7 @@ static void sd_rw_intr(struct scsi_cmnd break; } out:+ sd_iostats_finish_req(SCpnt); scsi_io_completion(SCpnt, good_bytes); }@@ -1575,6 +1643,481 @@ static void sd_shutdown(struct device *d sd_sync_cache(sdp); } +#if (defined(CONFIG_SD_IOSTATS) && defined(CONFIG_PROC_FS))+static int+sd_iostats_seq_show(struct seq_file *seq, void *v)+{+ struct timeval now;+ struct gendisk *disk = seq->private;+ iostat_stats_t *stats;+ unsigned long long read_len;+ unsigned long long read_len_tot;+ unsigned long read_num;+ unsigned long read_num_tot;+ unsigned long long write_len;+ unsigned long long write_len_tot;+ unsigned long write_num;+ unsigned long write_num_tot;+ int i;+ int maxi;++ if (sd_iostats == NULL) {+ printk(KERN_ERR "sd_iostats_seq_show: NULL stats array\n");+ BUG();+ }++ stats = sd_iostats[scsi_disk(disk)->index];+ if (stats == NULL) {+ printk(KERN_ERR "sd_iostats_seq_show: NULL stats entry\n");+ BUG();+ }++ do_gettimeofday(&now);+ now.tv_sec -= stats->iostat_timeval.tv_sec;+ now.tv_usec -= stats->iostat_timeval.tv_usec;+ if (now.tv_usec < 0) {+ now.tv_usec += 1000000;+ now.tv_sec--;+ }++ /* this sampling races with updates */+ seq_printf(seq, "index: %lu snapshot_time: %lu.%06lu\n",+ (unsigned long) scsi_disk(disk)->index,+ now.tv_sec, now.tv_usec);++ for (i = IOSTAT_NCOUNTERS - 1; i > 0; i--)+ if (stats->iostat_read_histogram[i].iostat_count != 0 ||+ stats->iostat_write_histogram[i].iostat_count != 0)+ break;+ maxi = i;++ seq_printf(seq, "%8s %8s %12s %8s %12s\n", "size", + "reads", "total", "writes", "total");++ read_len_tot = write_len_tot = 0;+ read_num_tot = write_num_tot = 0;+ for (i = 0; i <= maxi; i++) {+ read_len = stats->iostat_read_histogram[i].iostat_size;+ read_len_tot += read_len;+ read_num = stats->iostat_read_histogram[i].iostat_count;+ read_num_tot += read_num;++ write_len = stats->iostat_write_histogram[i].iostat_size;+ write_len_tot += write_len;+ write_num = stats->iostat_write_histogram[i].iostat_count;+ write_num_tot += write_num;++ seq_printf (seq, "%8d %8lu %12llu %8lu %12llu\n", + 512<<i, read_num, read_len, write_num, write_len);+ }++ seq_printf(seq, "%8s %8lu %12llu %8lu %12llu\n\n", "total",+ read_num_tot, read_len_tot, + write_num_tot, write_len_tot);++ seq_printf(seq, "%8s %8s %8s\n", "qdepth", "ticks", "%");+ for (i = 0; i < IOSTAT_NCOUNTERS; i++) {+ unsigned long long ticks, percent;+ ticks = stats->iostat_queue_ticks[i];+ if (ticks == 0)+ continue;+ percent = stats->iostat_queue_ticks[i] * 100;+ do_div(percent, stats->iostat_queue_ticks_sum);+ seq_printf(seq, "%8d %8llu %8llu\n", i, ticks, percent);+ }++ if (stats->iostat_reqs != 0) {+ unsigned long long aveseek = 0, percent = 0;++ if (stats->iostat_seeks) {+ aveseek = stats->iostat_seek_sectors;+ do_div(aveseek, stats->iostat_seeks);+ percent = stats->iostat_seeks * 100;+ do_div(percent, stats->iostat_reqs);+ }++ seq_printf(seq, "\n%llu sectors in %llu reqs: %llu seek(s) over "+ "%llu sectors in ave, %llu%% of all reqs\n",+ stats->iostat_sectors, stats->iostat_reqs,+ stats->iostat_seeks, aveseek, percent);+ }++ seq_printf(seq, "\n%16s %8s %8s %8s %8s\n", "process time", "reads",+ "%%", "writes", "%%");+ for (i = 0; i < IOSTAT_NCOUNTERS; i++) {+ unsigned long read_percent = 0, write_percent = 0;+ if (stats->iostat_wtime[i] == 0 &&+ stats->iostat_rtime[i] == 0)+ continue;+ if (stats->iostat_read_reqs)+ read_percent = stats->iostat_rtime[i] * 100 / + stats->iostat_read_reqs;+ if (stats->iostat_write_reqs)+ write_percent = stats->iostat_wtime[i] * 100 / + stats->iostat_write_reqs;+ seq_printf(seq, "%16u %8lu %8lu %8lu %8lu\n",+ jiffies_to_msecs(((1UL << i) >> 1) << 1),+ stats->iostat_rtime[i], read_percent,+ stats->iostat_wtime[i], write_percent);+ }++ seq_printf(seq, "\n%16s %8s %8s %8s %8s\n", "time in queue", "reads",+ "%%", "writes", "%%");+ for (i = 0; i < IOSTAT_NCOUNTERS; i++) {+ unsigned long read_percent = 0, write_percent = 0;+ if (stats->iostat_wtime_in_queue[i] == 0 &&+ stats->iostat_rtime_in_queue[i] == 0)+ continue;+ if (stats->iostat_read_reqs)+ read_percent = stats->iostat_rtime_in_queue[i] * 100 / + stats->iostat_read_reqs;+ if (stats->iostat_write_reqs)+ write_percent = stats->iostat_wtime_in_queue[i] * 100 / + stats->iostat_write_reqs;+ seq_printf(seq, "%16u %8lu %8lu %8lu %8lu\n",+ jiffies_to_msecs(((1UL << i) >> 1) << 1),+ stats->iostat_rtime_in_queue[i],+ read_percent,+ stats->iostat_wtime_in_queue[i],+ write_percent);+ }++ return 0;+}++static void *+sd_iostats_seq_start(struct seq_file *p, loff_t *pos)+{+ return (*pos == 0) ? (void *)1 : NULL;+}++static void *+sd_iostats_seq_next(struct seq_file *p, void *v, loff_t *pos)+{+ ++*pos;+ return NULL;+}++static void+sd_iostats_seq_stop(struct seq_file *p, void *v)+{+}++static struct seq_operations sd_iostats_seqops = {+ .start = sd_iostats_seq_start,+ .stop = sd_iostats_seq_stop,+ .next = sd_iostats_seq_next,+ .show = sd_iostats_seq_show,+};++static int+sd_iostats_seq_open (struct inode *inode, struct file *file)+{+ int rc;++ rc = seq_open(file, &sd_iostats_seqops);+ if (rc != 0)+ return rc;++ ((struct seq_file *)file->private_data)->private = PDE(inode)->data;+ return 0;+}++static ssize_t+sd_iostats_seq_write(struct file *file, const char *buffer,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -