123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320 |
- /*
- * File...........: linux/drivers/s390/block/dasd_proc.c
- * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- * Horst Hummel <Horst.Hummel@de.ibm.com>
- * Carsten Otte <Cotte@de.ibm.com>
- * Martin Schwidefsky <schwidefsky@de.ibm.com>
- * Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2002
- *
- * /proc interface for the dasd driver.
- *
- * $Revision: 1.33 $
- */
- #include <linux/config.h>
- #include <linux/ctype.h>
- #include <linux/seq_file.h>
- #include <linux/vmalloc.h>
- #include <linux/proc_fs.h>
- #include <asm/debug.h>
- #include <asm/uaccess.h>
- /* This is ugly... */
- #define PRINTK_HEADER "dasd_proc:"
- #include "dasd_int.h"
- static struct proc_dir_entry *dasd_proc_root_entry = NULL;
- static struct proc_dir_entry *dasd_devices_entry = NULL;
- static struct proc_dir_entry *dasd_statistics_entry = NULL;
- static inline char *
- dasd_get_user_string(const char __user *user_buf, size_t user_len)
- {
- char *buffer;
- buffer = kmalloc(user_len + 1, GFP_KERNEL);
- if (buffer == NULL)
- return ERR_PTR(-ENOMEM);
- if (copy_from_user(buffer, user_buf, user_len) != 0) {
- kfree(buffer);
- return ERR_PTR(-EFAULT);
- }
- /* got the string, now strip linefeed. */
- if (buffer[user_len - 1] == '\n')
- buffer[user_len - 1] = 0;
- else
- buffer[user_len] = 0;
- return buffer;
- }
- static int
- dasd_devices_show(struct seq_file *m, void *v)
- {
- struct dasd_device *device;
- char *substr;
- device = dasd_device_from_devindex((unsigned long) v - 1);
- if (IS_ERR(device))
- return 0;
- /* Print device number. */
- seq_printf(m, "%s", device->cdev->dev.bus_id);
- /* Print discipline string. */
- if (device != NULL && device->discipline != NULL)
- seq_printf(m, "(%s)", device->discipline->name);
- else
- seq_printf(m, "(none)");
- /* Print kdev. */
- if (device->gdp)
- seq_printf(m, " at (%3d:%6d)",
- device->gdp->major, device->gdp->first_minor);
- else
- seq_printf(m, " at (???:??????)");
- /* Print device name. */
- if (device->gdp)
- seq_printf(m, " is %-8s", device->gdp->disk_name);
- else
- seq_printf(m, " is ????????");
- /* Print devices features. */
- substr = (device->features & DASD_FEATURE_READONLY) ? "(ro)" : " ";
- seq_printf(m, "%4s: ", substr);
- /* Print device status information. */
- switch ((device != NULL) ? device->state : -1) {
- case -1:
- seq_printf(m, "unknown");
- break;
- case DASD_STATE_NEW:
- seq_printf(m, "new");
- break;
- case DASD_STATE_KNOWN:
- seq_printf(m, "detected");
- break;
- case DASD_STATE_BASIC:
- seq_printf(m, "basic");
- break;
- case DASD_STATE_READY:
- case DASD_STATE_ONLINE:
- seq_printf(m, "active ");
- if (dasd_check_blocksize(device->bp_block))
- seq_printf(m, "n/f ");
- else
- seq_printf(m,
- "at blocksize: %d, %ld blocks, %ld MB",
- device->bp_block, device->blocks,
- ((device->bp_block >> 9) *
- device->blocks) >> 11);
- break;
- default:
- seq_printf(m, "no stat");
- break;
- }
- dasd_put_device(device);
- if (dasd_probeonly)
- seq_printf(m, "(probeonly)");
- seq_printf(m, "\n");
- return 0;
- }
- static void *dasd_devices_start(struct seq_file *m, loff_t *pos)
- {
- if (*pos >= dasd_max_devindex)
- return NULL;
- return (void *)((unsigned long) *pos + 1);
- }
- static void *dasd_devices_next(struct seq_file *m, void *v, loff_t *pos)
- {
- ++*pos;
- return dasd_devices_start(m, pos);
- }
- static void dasd_devices_stop(struct seq_file *m, void *v)
- {
- }
- static struct seq_operations dasd_devices_seq_ops = {
- .start = dasd_devices_start,
- .next = dasd_devices_next,
- .stop = dasd_devices_stop,
- .show = dasd_devices_show,
- };
- static int dasd_devices_open(struct inode *inode, struct file *file)
- {
- return seq_open(file, &dasd_devices_seq_ops);
- }
- static struct file_operations dasd_devices_file_ops = {
- .open = dasd_devices_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release,
- };
- static inline int
- dasd_calc_metrics(char *page, char **start, off_t off,
- int count, int *eof, int len)
- {
- len = (len > off) ? len - off : 0;
- if (len > count)
- len = count;
- if (len < count)
- *eof = 1;
- *start = page + off;
- return len;
- }
- static inline char *
- dasd_statistics_array(char *str, int *array, int shift)
- {
- int i;
- for (i = 0; i < 32; i++) {
- str += sprintf(str, "%7d ", array[i] >> shift);
- if (i == 15)
- str += sprintf(str, "\n");
- }
- str += sprintf(str,"\n");
- return str;
- }
- static int
- dasd_statistics_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
- {
- unsigned long len;
- #ifdef CONFIG_DASD_PROFILE
- struct dasd_profile_info_t *prof;
- char *str;
- int shift;
- /* check for active profiling */
- if (dasd_profile_level == DASD_PROFILE_OFF) {
- len = sprintf(page, "Statistics are off - they might be "
- "switched on using 'echo set on > "
- "/proc/dasd/statistics'\n");
- return dasd_calc_metrics(page, start, off, count, eof, len);
- }
- prof = &dasd_global_profile;
- /* prevent couter 'overflow' on output */
- for (shift = 0; (prof->dasd_io_reqs >> shift) > 9999999; shift++);
- str = page;
- str += sprintf(str, "%d dasd I/O requests\n", prof->dasd_io_reqs);
- str += sprintf(str, "with %d sectors(512B each)\n",
- prof->dasd_io_sects);
- str += sprintf(str,
- " __<4 ___8 __16 __32 __64 _128 "
- " _256 _512 __1k __2k __4k __8k "
- " _16k _32k _64k 128k\n");
- str += sprintf(str,
- " _256 _512 __1M __2M __4M __8M "
- " _16M _32M _64M 128M 256M 512M "
- " __1G __2G __4G " " _>4G\n");
- str += sprintf(str, "Histogram of sizes (512B secs)\n");
- str = dasd_statistics_array(str, prof->dasd_io_secs, shift);
- str += sprintf(str, "Histogram of I/O times (microseconds)\n");
- str = dasd_statistics_array(str, prof->dasd_io_times, shift);
- str += sprintf(str, "Histogram of I/O times per sector\n");
- str = dasd_statistics_array(str, prof->dasd_io_timps, shift);
- str += sprintf(str, "Histogram of I/O time till ssch\n");
- str = dasd_statistics_array(str, prof->dasd_io_time1, shift);
- str += sprintf(str, "Histogram of I/O time between ssch and irq\n");
- str = dasd_statistics_array(str, prof->dasd_io_time2, shift);
- str += sprintf(str, "Histogram of I/O time between ssch "
- "and irq per sector\n");
- str = dasd_statistics_array(str, prof->dasd_io_time2ps, shift);
- str += sprintf(str, "Histogram of I/O time between irq and end\n");
- str = dasd_statistics_array(str, prof->dasd_io_time3, shift);
- str += sprintf(str, "# of req in chanq at enqueuing (1..32) \n");
- str = dasd_statistics_array(str, prof->dasd_io_nr_req, shift);
- len = str - page;
- #else
- len = sprintf(page, "Statistics are not activated in this kernel\n");
- #endif
- return dasd_calc_metrics(page, start, off, count, eof, len);
- }
- static int
- dasd_statistics_write(struct file *file, const char __user *user_buf,
- unsigned long user_len, void *data)
- {
- #ifdef CONFIG_DASD_PROFILE
- char *buffer, *str;
- if (user_len > 65536)
- user_len = 65536;
- buffer = dasd_get_user_string(user_buf, user_len);
- if (IS_ERR(buffer))
- return PTR_ERR(buffer);
- MESSAGE_LOG(KERN_INFO, "/proc/dasd/statictics: '%s'", buffer);
- /* check for valid verbs */
- for (str = buffer; isspace(*str); str++);
- if (strncmp(str, "set", 3) == 0 && isspace(str[3])) {
- /* 'set xxx' was given */
- for (str = str + 4; isspace(*str); str++);
- if (strcmp(str, "on") == 0) {
- /* switch on statistics profiling */
- dasd_profile_level = DASD_PROFILE_ON;
- MESSAGE(KERN_INFO, "%s", "Statistics switched on");
- } else if (strcmp(str, "off") == 0) {
- /* switch off and reset statistics profiling */
- memset(&dasd_global_profile,
- 0, sizeof (struct dasd_profile_info_t));
- dasd_profile_level = DASD_PROFILE_OFF;
- MESSAGE(KERN_INFO, "%s", "Statistics switched off");
- } else
- goto out_error;
- } else if (strncmp(str, "reset", 5) == 0) {
- /* reset the statistics */
- memset(&dasd_global_profile, 0,
- sizeof (struct dasd_profile_info_t));
- MESSAGE(KERN_INFO, "%s", "Statistics reset");
- } else
- goto out_error;
- kfree(buffer);
- return user_len;
- out_error:
- MESSAGE(KERN_WARNING, "%s",
- "/proc/dasd/statistics: only 'set on', 'set off' "
- "and 'reset' are supported verbs");
- kfree(buffer);
- return -EINVAL;
- #else
- MESSAGE(KERN_WARNING, "%s",
- "/proc/dasd/statistics: is not activated in this kernel");
- return user_len;
- #endif /* CONFIG_DASD_PROFILE */
- }
- int
- dasd_proc_init(void)
- {
- dasd_proc_root_entry = proc_mkdir("dasd", &proc_root);
- dasd_proc_root_entry->owner = THIS_MODULE;
- dasd_devices_entry = create_proc_entry("devices",
- S_IFREG | S_IRUGO | S_IWUSR,
- dasd_proc_root_entry);
- dasd_devices_entry->proc_fops = &dasd_devices_file_ops;
- dasd_devices_entry->owner = THIS_MODULE;
- dasd_statistics_entry = create_proc_entry("statistics",
- S_IFREG | S_IRUGO | S_IWUSR,
- dasd_proc_root_entry);
- dasd_statistics_entry->read_proc = dasd_statistics_read;
- dasd_statistics_entry->write_proc = dasd_statistics_write;
- dasd_statistics_entry->owner = THIS_MODULE;
- return 0;
- }
- void
- dasd_proc_exit(void)
- {
- remove_proc_entry("devices", dasd_proc_root_entry);
- remove_proc_entry("statistics", dasd_proc_root_entry);
- remove_proc_entry("dasd", &proc_root);
- }
|