aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/block/dasd_proc.c
diff options
context:
space:
mode:
authorStefan Weinhuber <wein@de.ibm.com>2011-07-24 04:48:32 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2011-07-24 04:48:23 -0400
commit4fa52aa7a82f9226b3874a69816bda3af821f002 (patch)
tree7d61364211cf22bb942b5eff7286c3c1f037fdf0 /drivers/s390/block/dasd_proc.c
parent8bb3a2ebcf2a406a60d04f5a8756ea936b7f0bf3 (diff)
[S390] dasd: add enhanced DASD statistics interface
This patch extends the DASD statistics to allow for a more detailed analysis of DASD I/O operations. In particular we want the statistics to provide answers to the following questions: - How many requests used a PAV alias? - How many requests used High Performance FICON? - How do read request perform versus write requests? The existing DASD statistics interface has several shortcomings - The interface for global data is a formatted text table in procfs (/proc/dasd/statistics). The layout is meant for human readers and is not to easy to parse. If values get to large for the table layout, they get scaled down. - The statistics which are collected per block device can be accessed via an ioctl interface, which can only be extended by defining a new ioctl. - There is no statistics interface for individual PAV base and alias devices. To overcome theses shortcomings we create a new DASD statistics interface in debugfs. This interface will contain one entry for global data, one per DASD block device, and one per DASD base and alias device. Each file contains the statistic data in easy to parse name/value and name/array pairs. The existing interfaces will remain functional, but they will not be extended. Signed-off-by: Stefan Weinhuber <wein@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/block/dasd_proc.c')
-rw-r--r--drivers/s390/block/dasd_proc.c106
1 files changed, 71 insertions, 35 deletions
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
index c4a6a31bd9cd..6c3c5364d082 100644
--- a/drivers/s390/block/dasd_proc.c
+++ b/drivers/s390/block/dasd_proc.c
@@ -32,28 +32,6 @@ static struct proc_dir_entry *dasd_proc_root_entry = NULL;
32static struct proc_dir_entry *dasd_devices_entry = NULL; 32static struct proc_dir_entry *dasd_devices_entry = NULL;
33static struct proc_dir_entry *dasd_statistics_entry = NULL; 33static struct proc_dir_entry *dasd_statistics_entry = NULL;
34 34
35#ifdef CONFIG_DASD_PROFILE
36static char *
37dasd_get_user_string(const char __user *user_buf, size_t user_len)
38{
39 char *buffer;
40
41 buffer = kmalloc(user_len + 1, GFP_KERNEL);
42 if (buffer == NULL)
43 return ERR_PTR(-ENOMEM);
44 if (copy_from_user(buffer, user_buf, user_len) != 0) {
45 kfree(buffer);
46 return ERR_PTR(-EFAULT);
47 }
48 /* got the string, now strip linefeed. */
49 if (buffer[user_len - 1] == '\n')
50 buffer[user_len - 1] = 0;
51 else
52 buffer[user_len] = 0;
53 return buffer;
54}
55#endif /* CONFIG_DASD_PROFILE */
56
57static int 35static int
58dasd_devices_show(struct seq_file *m, void *v) 36dasd_devices_show(struct seq_file *m, void *v)
59{ 37{
@@ -167,6 +145,55 @@ static const struct file_operations dasd_devices_file_ops = {
167}; 145};
168 146
169#ifdef CONFIG_DASD_PROFILE 147#ifdef CONFIG_DASD_PROFILE
148static int dasd_stats_all_block_on(void)
149{
150 int i, rc;
151 struct dasd_device *device;
152
153 rc = 0;
154 for (i = 0; i < dasd_max_devindex; ++i) {
155 device = dasd_device_from_devindex(i);
156 if (IS_ERR(device))
157 continue;
158 if (device->block)
159 rc = dasd_profile_on(&device->block->profile);
160 dasd_put_device(device);
161 if (rc)
162 return rc;
163 }
164 return 0;
165}
166
167static void dasd_stats_all_block_off(void)
168{
169 int i;
170 struct dasd_device *device;
171
172 for (i = 0; i < dasd_max_devindex; ++i) {
173 device = dasd_device_from_devindex(i);
174 if (IS_ERR(device))
175 continue;
176 if (device->block)
177 dasd_profile_off(&device->block->profile);
178 dasd_put_device(device);
179 }
180}
181
182static void dasd_stats_all_block_reset(void)
183{
184 int i;
185 struct dasd_device *device;
186
187 for (i = 0; i < dasd_max_devindex; ++i) {
188 device = dasd_device_from_devindex(i);
189 if (IS_ERR(device))
190 continue;
191 if (device->block)
192 dasd_profile_reset(&device->block->profile);
193 dasd_put_device(device);
194 }
195}
196
170static void dasd_statistics_array(struct seq_file *m, unsigned int *array, int factor) 197static void dasd_statistics_array(struct seq_file *m, unsigned int *array, int factor)
171{ 198{
172 int i; 199 int i;
@@ -183,18 +210,18 @@ static void dasd_statistics_array(struct seq_file *m, unsigned int *array, int f
183static int dasd_stats_proc_show(struct seq_file *m, void *v) 210static int dasd_stats_proc_show(struct seq_file *m, void *v)
184{ 211{
185#ifdef CONFIG_DASD_PROFILE 212#ifdef CONFIG_DASD_PROFILE
186 struct dasd_profile_info_t *prof; 213 struct dasd_profile_info *prof;
187 int factor; 214 int factor;
188 215
189 /* check for active profiling */ 216 /* check for active profiling */
190 if (dasd_profile_level == DASD_PROFILE_OFF) { 217 if (!dasd_global_profile_level) {
191 seq_printf(m, "Statistics are off - they might be " 218 seq_printf(m, "Statistics are off - they might be "
192 "switched on using 'echo set on > " 219 "switched on using 'echo set on > "
193 "/proc/dasd/statistics'\n"); 220 "/proc/dasd/statistics'\n");
194 return 0; 221 return 0;
195 } 222 }
223 prof = &dasd_global_profile_data;
196 224
197 prof = &dasd_global_profile;
198 /* prevent counter 'overflow' on output */ 225 /* prevent counter 'overflow' on output */
199 for (factor = 1; (prof->dasd_io_reqs / factor) > 9999999; 226 for (factor = 1; (prof->dasd_io_reqs / factor) > 9999999;
200 factor *= 10); 227 factor *= 10);
@@ -245,6 +272,7 @@ static ssize_t dasd_stats_proc_write(struct file *file,
245{ 272{
246#ifdef CONFIG_DASD_PROFILE 273#ifdef CONFIG_DASD_PROFILE
247 char *buffer, *str; 274 char *buffer, *str;
275 int rc;
248 276
249 if (user_len > 65536) 277 if (user_len > 65536)
250 user_len = 65536; 278 user_len = 65536;
@@ -259,32 +287,40 @@ static ssize_t dasd_stats_proc_write(struct file *file,
259 str = skip_spaces(str + 4); 287 str = skip_spaces(str + 4);
260 if (strcmp(str, "on") == 0) { 288 if (strcmp(str, "on") == 0) {
261 /* switch on statistics profiling */ 289 /* switch on statistics profiling */
262 dasd_profile_level = DASD_PROFILE_ON; 290 rc = dasd_stats_all_block_on();
291 if (rc) {
292 dasd_stats_all_block_off();
293 goto out_error;
294 }
295 dasd_global_profile_reset();
296 dasd_global_profile_level = DASD_PROFILE_ON;
263 pr_info("The statistics feature has been switched " 297 pr_info("The statistics feature has been switched "
264 "on\n"); 298 "on\n");
265 } else if (strcmp(str, "off") == 0) { 299 } else if (strcmp(str, "off") == 0) {
266 /* switch off and reset statistics profiling */ 300 /* switch off and reset statistics profiling */
267 memset(&dasd_global_profile, 301 dasd_global_profile_level = DASD_PROFILE_OFF;
268 0, sizeof (struct dasd_profile_info_t)); 302 dasd_global_profile_reset();
269 dasd_profile_level = DASD_PROFILE_OFF; 303 dasd_stats_all_block_off();
270 pr_info("The statistics feature has been switched " 304 pr_info("The statistics feature has been switched "
271 "off\n"); 305 "off\n");
272 } else 306 } else
273 goto out_error; 307 goto out_parse_error;
274 } else if (strncmp(str, "reset", 5) == 0) { 308 } else if (strncmp(str, "reset", 5) == 0) {
275 /* reset the statistics */ 309 /* reset the statistics */
276 memset(&dasd_global_profile, 0, 310 dasd_global_profile_reset();
277 sizeof (struct dasd_profile_info_t)); 311 dasd_stats_all_block_reset();
278 pr_info("The statistics have been reset\n"); 312 pr_info("The statistics have been reset\n");
279 } else 313 } else
280 goto out_error; 314 goto out_parse_error;
281 kfree(buffer); 315 kfree(buffer);
282 return user_len; 316 return user_len;
283out_error: 317out_parse_error:
318 rc = -EINVAL;
284 pr_warning("%s is not a supported value for /proc/dasd/statistics\n", 319 pr_warning("%s is not a supported value for /proc/dasd/statistics\n",
285 str); 320 str);
321out_error:
286 kfree(buffer); 322 kfree(buffer);
287 return -EINVAL; 323 return rc;
288#else 324#else
289 pr_warning("/proc/dasd/statistics: is not activated in this kernel\n"); 325 pr_warning("/proc/dasd/statistics: is not activated in this kernel\n");
290 return user_len; 326 return user_len;