diff options
author | Sebastian Ott <sebott@linux.vnet.ibm.com> | 2015-01-28 12:44:17 -0500 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2015-01-29 03:19:27 -0500 |
commit | 8ea55c95c372a7a51fa50cb7c75240bfbe8bd337 (patch) | |
tree | a7a496ce7f0f0ae9a417d50acb44fb9fe1229ff9 /drivers/s390 | |
parent | e6d60b368b45b9be3aa068f8e5fa98c3487c9d4e (diff) |
s390/dasd: add locking for global_profile access
Access to DASDs global statistics is done without locking which
can lead to inconsistent data. Add locking to fix this. Also move
the relevant structs in a global dasd_profile struct.
Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Reviewed-by: Stefan Haberland <stefan.haberland@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/block/dasd.c | 32 | ||||
-rw-r--r-- | drivers/s390/block/dasd_int.h | 2 | ||||
-rw-r--r-- | drivers/s390/block/dasd_proc.c | 4 |
3 files changed, 24 insertions, 14 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 4abf11965484..a67e8dae73c3 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c | |||
@@ -674,8 +674,12 @@ EXPORT_SYMBOL(dasd_enable_device); | |||
674 | unsigned int dasd_global_profile_level = DASD_PROFILE_OFF; | 674 | unsigned int dasd_global_profile_level = DASD_PROFILE_OFF; |
675 | 675 | ||
676 | #ifdef CONFIG_DASD_PROFILE | 676 | #ifdef CONFIG_DASD_PROFILE |
677 | struct dasd_profile_info dasd_global_profile_data; | 677 | static struct dasd_profile_info dasd_global_profile_data; |
678 | static struct dentry *dasd_global_profile_dentry; | 678 | struct dasd_profile dasd_global_profile = { |
679 | .dentry = NULL, | ||
680 | .data = &dasd_global_profile_data, | ||
681 | .lock = __SPIN_LOCK_UNLOCKED(dasd_global_profile.lock), | ||
682 | }; | ||
679 | static struct dentry *dasd_debugfs_global_entry; | 683 | static struct dentry *dasd_debugfs_global_entry; |
680 | 684 | ||
681 | /* | 685 | /* |
@@ -696,11 +700,13 @@ static void dasd_profile_start(struct dasd_block *block, | |||
696 | if (++counter >= 31) | 700 | if (++counter >= 31) |
697 | break; | 701 | break; |
698 | 702 | ||
703 | spin_lock(&dasd_global_profile.lock); | ||
699 | if (dasd_global_profile_level) { | 704 | if (dasd_global_profile_level) { |
700 | dasd_global_profile_data.dasd_io_nr_req[counter]++; | 705 | dasd_global_profile.data->dasd_io_nr_req[counter]++; |
701 | if (rq_data_dir(req) == READ) | 706 | if (rq_data_dir(req) == READ) |
702 | dasd_global_profile_data.dasd_read_nr_req[counter]++; | 707 | dasd_global_profile.data->dasd_read_nr_req[counter]++; |
703 | } | 708 | } |
709 | spin_unlock(&dasd_global_profile.lock); | ||
704 | 710 | ||
705 | spin_lock(&block->profile.lock); | 711 | spin_lock(&block->profile.lock); |
706 | if (block->profile.data) { | 712 | if (block->profile.data) { |
@@ -825,8 +831,9 @@ static void dasd_profile_end(struct dasd_block *block, | |||
825 | dasd_profile_counter(irqtime / sectors, irqtimeps_ind); | 831 | dasd_profile_counter(irqtime / sectors, irqtimeps_ind); |
826 | dasd_profile_counter(endtime, endtime_ind); | 832 | dasd_profile_counter(endtime, endtime_ind); |
827 | 833 | ||
834 | spin_lock(&dasd_global_profile.lock); | ||
828 | if (dasd_global_profile_level) { | 835 | if (dasd_global_profile_level) { |
829 | dasd_profile_end_add_data(&dasd_global_profile_data, | 836 | dasd_profile_end_add_data(dasd_global_profile.data, |
830 | cqr->startdev != block->base, | 837 | cqr->startdev != block->base, |
831 | cqr->cpmode == 1, | 838 | cqr->cpmode == 1, |
832 | rq_data_dir(req) == READ, | 839 | rq_data_dir(req) == READ, |
@@ -835,6 +842,7 @@ static void dasd_profile_end(struct dasd_block *block, | |||
835 | irqtime_ind, irqtimeps_ind, | 842 | irqtime_ind, irqtimeps_ind, |
836 | endtime_ind); | 843 | endtime_ind); |
837 | } | 844 | } |
845 | spin_unlock(&dasd_global_profile.lock); | ||
838 | 846 | ||
839 | spin_lock(&block->profile.lock); | 847 | spin_lock(&block->profile.lock); |
840 | if (block->profile.data) | 848 | if (block->profile.data) |
@@ -878,8 +886,7 @@ void dasd_profile_reset(struct dasd_profile *profile) | |||
878 | 886 | ||
879 | void dasd_global_profile_reset(void) | 887 | void dasd_global_profile_reset(void) |
880 | { | 888 | { |
881 | memset(&dasd_global_profile_data, 0, sizeof(dasd_global_profile_data)); | 889 | dasd_profile_reset(&dasd_global_profile); |
882 | getnstimeofday(&dasd_global_profile_data.starttod); | ||
883 | } | 890 | } |
884 | 891 | ||
885 | int dasd_profile_on(struct dasd_profile *profile) | 892 | int dasd_profile_on(struct dasd_profile *profile) |
@@ -1077,7 +1084,9 @@ static int dasd_stats_global_show(struct seq_file *m, void *v) | |||
1077 | seq_puts(m, "disabled\n"); | 1084 | seq_puts(m, "disabled\n"); |
1078 | return 0; | 1085 | return 0; |
1079 | } | 1086 | } |
1080 | dasd_stats_seq_print(m, &dasd_global_profile_data); | 1087 | spin_lock_bh(&dasd_global_profile.lock); |
1088 | dasd_stats_seq_print(m, dasd_global_profile.data); | ||
1089 | spin_unlock_bh(&dasd_global_profile.lock); | ||
1081 | return 0; | 1090 | return 0; |
1082 | } | 1091 | } |
1083 | 1092 | ||
@@ -1123,8 +1132,8 @@ static void dasd_profile_exit(struct dasd_profile *profile) | |||
1123 | static void dasd_statistics_removeroot(void) | 1132 | static void dasd_statistics_removeroot(void) |
1124 | { | 1133 | { |
1125 | dasd_global_profile_level = DASD_PROFILE_OFF; | 1134 | dasd_global_profile_level = DASD_PROFILE_OFF; |
1126 | debugfs_remove(dasd_global_profile_dentry); | 1135 | debugfs_remove(dasd_global_profile.dentry); |
1127 | dasd_global_profile_dentry = NULL; | 1136 | dasd_global_profile.dentry = NULL; |
1128 | debugfs_remove(dasd_debugfs_global_entry); | 1137 | debugfs_remove(dasd_debugfs_global_entry); |
1129 | debugfs_remove(dasd_debugfs_root_entry); | 1138 | debugfs_remove(dasd_debugfs_root_entry); |
1130 | } | 1139 | } |
@@ -1136,7 +1145,6 @@ static void dasd_statistics_createroot(void) | |||
1136 | 1145 | ||
1137 | dasd_debugfs_root_entry = NULL; | 1146 | dasd_debugfs_root_entry = NULL; |
1138 | dasd_debugfs_global_entry = NULL; | 1147 | dasd_debugfs_global_entry = NULL; |
1139 | dasd_global_profile_dentry = NULL; | ||
1140 | pde = debugfs_create_dir("dasd", NULL); | 1148 | pde = debugfs_create_dir("dasd", NULL); |
1141 | if (!pde || IS_ERR(pde)) | 1149 | if (!pde || IS_ERR(pde)) |
1142 | goto error; | 1150 | goto error; |
@@ -1151,7 +1159,7 @@ static void dasd_statistics_createroot(void) | |||
1151 | NULL, &dasd_stats_global_fops); | 1159 | NULL, &dasd_stats_global_fops); |
1152 | if (!pde || IS_ERR(pde)) | 1160 | if (!pde || IS_ERR(pde)) |
1153 | goto error; | 1161 | goto error; |
1154 | dasd_global_profile_dentry = pde; | 1162 | dasd_global_profile.dentry = pde; |
1155 | return; | 1163 | return; |
1156 | 1164 | ||
1157 | error: | 1165 | error: |
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 8b5d4100abf7..91731fa05604 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h | |||
@@ -651,7 +651,7 @@ dasd_check_blocksize(int bsize) | |||
651 | #define DASD_PROFILE_GLOBAL_ONLY 2 | 651 | #define DASD_PROFILE_GLOBAL_ONLY 2 |
652 | 652 | ||
653 | extern debug_info_t *dasd_debug_area; | 653 | extern debug_info_t *dasd_debug_area; |
654 | extern struct dasd_profile_info dasd_global_profile_data; | 654 | extern struct dasd_profile dasd_global_profile; |
655 | extern unsigned int dasd_global_profile_level; | 655 | extern unsigned int dasd_global_profile_level; |
656 | extern const struct block_device_operations dasd_device_operations; | 656 | extern const struct block_device_operations dasd_device_operations; |
657 | 657 | ||
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index 78ac905a5b7f..76410084c48f 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c | |||
@@ -219,7 +219,8 @@ static int dasd_stats_proc_show(struct seq_file *m, void *v) | |||
219 | "/proc/dasd/statistics'\n"); | 219 | "/proc/dasd/statistics'\n"); |
220 | return 0; | 220 | return 0; |
221 | } | 221 | } |
222 | prof = &dasd_global_profile_data; | 222 | spin_lock_bh(&dasd_global_profile.lock); |
223 | prof = dasd_global_profile.data; | ||
223 | 224 | ||
224 | /* prevent counter 'overflow' on output */ | 225 | /* prevent counter 'overflow' on output */ |
225 | for (factor = 1; (prof->dasd_io_reqs / factor) > 9999999; | 226 | for (factor = 1; (prof->dasd_io_reqs / factor) > 9999999; |
@@ -255,6 +256,7 @@ static int dasd_stats_proc_show(struct seq_file *m, void *v) | |||
255 | dasd_statistics_array(m, prof->dasd_io_time3, factor); | 256 | dasd_statistics_array(m, prof->dasd_io_time3, factor); |
256 | seq_printf(m, "# of req in chanq at enqueuing (1..32) \n"); | 257 | seq_printf(m, "# of req in chanq at enqueuing (1..32) \n"); |
257 | dasd_statistics_array(m, prof->dasd_io_nr_req, factor); | 258 | dasd_statistics_array(m, prof->dasd_io_nr_req, factor); |
259 | spin_unlock_bh(&dasd_global_profile.lock); | ||
258 | #else | 260 | #else |
259 | seq_printf(m, "Statistics are not activated in this kernel\n"); | 261 | seq_printf(m, "Statistics are not activated in this kernel\n"); |
260 | #endif | 262 | #endif |