cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dasd_proc.c (9707B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
      4 *		    Horst Hummel <Horst.Hummel@de.ibm.com>
      5 *		    Carsten Otte <Cotte@de.ibm.com>
      6 *		    Martin Schwidefsky <schwidefsky@de.ibm.com>
      7 * Bugreports.to..: <Linux390@de.ibm.com>
      8 * Copyright IBM Corp. 1999, 2002
      9 *
     10 * /proc interface for the dasd driver.
     11 *
     12 */
     13
     14#define KMSG_COMPONENT "dasd"
     15
     16#include <linux/ctype.h>
     17#include <linux/slab.h>
     18#include <linux/string.h>
     19#include <linux/seq_file.h>
     20#include <linux/vmalloc.h>
     21#include <linux/proc_fs.h>
     22
     23#include <asm/debug.h>
     24#include <linux/uaccess.h>
     25
     26/* This is ugly... */
     27#define PRINTK_HEADER "dasd_proc:"
     28
     29#include "dasd_int.h"
     30
     31static struct proc_dir_entry *dasd_proc_root_entry = NULL;
     32static struct proc_dir_entry *dasd_devices_entry = NULL;
     33static struct proc_dir_entry *dasd_statistics_entry = NULL;
     34
     35static int
     36dasd_devices_show(struct seq_file *m, void *v)
     37{
     38	struct dasd_device *device;
     39	struct dasd_block *block;
     40	char *substr;
     41
     42	device = dasd_device_from_devindex((unsigned long) v - 1);
     43	if (IS_ERR(device))
     44		return 0;
     45	if (device->block)
     46		block = device->block;
     47	else {
     48		dasd_put_device(device);
     49		return 0;
     50	}
     51	/* Print device number. */
     52	seq_printf(m, "%s", dev_name(&device->cdev->dev));
     53	/* Print discipline string. */
     54	if (device->discipline != NULL)
     55		seq_printf(m, "(%s)", device->discipline->name);
     56	else
     57		seq_printf(m, "(none)");
     58	/* Print kdev. */
     59	if (block->gdp)
     60		seq_printf(m, " at (%3d:%6d)",
     61			   MAJOR(disk_devt(block->gdp)),
     62			   MINOR(disk_devt(block->gdp)));
     63	else
     64		seq_printf(m, "  at (???:??????)");
     65	/* Print device name. */
     66	if (block->gdp)
     67		seq_printf(m, " is %-8s", block->gdp->disk_name);
     68	else
     69		seq_printf(m, " is ????????");
     70	/* Print devices features. */
     71	substr = (device->features & DASD_FEATURE_READONLY) ? "(ro)" : " ";
     72	seq_printf(m, "%4s: ", substr);
     73	/* Print device status information. */
     74	switch (device->state) {
     75	case DASD_STATE_NEW:
     76		seq_printf(m, "new");
     77		break;
     78	case DASD_STATE_KNOWN:
     79		seq_printf(m, "detected");
     80		break;
     81	case DASD_STATE_BASIC:
     82		seq_printf(m, "basic");
     83		break;
     84	case DASD_STATE_UNFMT:
     85		seq_printf(m, "unformatted");
     86		break;
     87	case DASD_STATE_READY:
     88	case DASD_STATE_ONLINE:
     89		seq_printf(m, "active ");
     90		if (dasd_check_blocksize(block->bp_block))
     91			seq_printf(m, "n/f	 ");
     92		else
     93			seq_printf(m,
     94				   "at blocksize: %u, %lu blocks, %lu MB",
     95				   block->bp_block, block->blocks,
     96				   ((block->bp_block >> 9) *
     97				    block->blocks) >> 11);
     98		break;
     99	default:
    100		seq_printf(m, "no stat");
    101		break;
    102	}
    103	dasd_put_device(device);
    104	if (dasd_probeonly)
    105		seq_printf(m, "(probeonly)");
    106	seq_printf(m, "\n");
    107	return 0;
    108}
    109
    110static void *dasd_devices_start(struct seq_file *m, loff_t *pos)
    111{
    112	if (*pos >= dasd_max_devindex)
    113		return NULL;
    114	return (void *)((unsigned long) *pos + 1);
    115}
    116
    117static void *dasd_devices_next(struct seq_file *m, void *v, loff_t *pos)
    118{
    119	++*pos;
    120	return dasd_devices_start(m, pos);
    121}
    122
    123static void dasd_devices_stop(struct seq_file *m, void *v)
    124{
    125}
    126
    127static const struct seq_operations dasd_devices_seq_ops = {
    128	.start		= dasd_devices_start,
    129	.next		= dasd_devices_next,
    130	.stop		= dasd_devices_stop,
    131	.show		= dasd_devices_show,
    132};
    133
    134#ifdef CONFIG_DASD_PROFILE
    135static int dasd_stats_all_block_on(void)
    136{
    137	int i, rc;
    138	struct dasd_device *device;
    139
    140	rc = 0;
    141	for (i = 0; i < dasd_max_devindex; ++i) {
    142		device = dasd_device_from_devindex(i);
    143		if (IS_ERR(device))
    144			continue;
    145		if (device->block)
    146			rc = dasd_profile_on(&device->block->profile);
    147		dasd_put_device(device);
    148		if (rc)
    149			return rc;
    150	}
    151	return 0;
    152}
    153
    154static void dasd_stats_all_block_off(void)
    155{
    156	int i;
    157	struct dasd_device *device;
    158
    159	for (i = 0; i < dasd_max_devindex; ++i) {
    160		device = dasd_device_from_devindex(i);
    161		if (IS_ERR(device))
    162			continue;
    163		if (device->block)
    164			dasd_profile_off(&device->block->profile);
    165		dasd_put_device(device);
    166	}
    167}
    168
    169static void dasd_stats_all_block_reset(void)
    170{
    171	int i;
    172	struct dasd_device *device;
    173
    174	for (i = 0; i < dasd_max_devindex; ++i) {
    175		device = dasd_device_from_devindex(i);
    176		if (IS_ERR(device))
    177			continue;
    178		if (device->block)
    179			dasd_profile_reset(&device->block->profile);
    180		dasd_put_device(device);
    181	}
    182}
    183
    184static void dasd_statistics_array(struct seq_file *m, unsigned int *array, int factor)
    185{
    186	int i;
    187
    188	for (i = 0; i < 32; i++) {
    189		seq_printf(m, "%7d ", array[i] / factor);
    190		if (i == 15)
    191			seq_putc(m, '\n');
    192	}
    193	seq_putc(m, '\n');
    194}
    195#endif /* CONFIG_DASD_PROFILE */
    196
    197static int dasd_stats_proc_show(struct seq_file *m, void *v)
    198{
    199#ifdef CONFIG_DASD_PROFILE
    200	struct dasd_profile_info *prof;
    201	int factor;
    202
    203	spin_lock_bh(&dasd_global_profile.lock);
    204	prof = dasd_global_profile.data;
    205	if (!prof) {
    206		spin_unlock_bh(&dasd_global_profile.lock);
    207		seq_printf(m, "Statistics are off - they might be "
    208				    "switched on using 'echo set on > "
    209				    "/proc/dasd/statistics'\n");
    210		return 0;
    211	}
    212
    213	/* prevent counter 'overflow' on output */
    214	for (factor = 1; (prof->dasd_io_reqs / factor) > 9999999;
    215	     factor *= 10);
    216
    217	seq_printf(m, "%d dasd I/O requests\n", prof->dasd_io_reqs);
    218	seq_printf(m, "with %u sectors(512B each)\n",
    219		       prof->dasd_io_sects);
    220	seq_printf(m, "Scale Factor is  %d\n", factor);
    221	seq_printf(m,
    222		       "   __<4	   ___8	   __16	   __32	   __64	   _128	"
    223		       "   _256	   _512	   __1k	   __2k	   __4k	   __8k	"
    224		       "   _16k	   _32k	   _64k	   128k\n");
    225	seq_printf(m,
    226		       "   _256	   _512	   __1M	   __2M	   __4M	   __8M	"
    227		       "   _16M	   _32M	   _64M	   128M	   256M	   512M	"
    228		       "   __1G	   __2G	   __4G " "   _>4G\n");
    229
    230	seq_printf(m, "Histogram of sizes (512B secs)\n");
    231	dasd_statistics_array(m, prof->dasd_io_secs, factor);
    232	seq_printf(m, "Histogram of I/O times (microseconds)\n");
    233	dasd_statistics_array(m, prof->dasd_io_times, factor);
    234	seq_printf(m, "Histogram of I/O times per sector\n");
    235	dasd_statistics_array(m, prof->dasd_io_timps, factor);
    236	seq_printf(m, "Histogram of I/O time till ssch\n");
    237	dasd_statistics_array(m, prof->dasd_io_time1, factor);
    238	seq_printf(m, "Histogram of I/O time between ssch and irq\n");
    239	dasd_statistics_array(m, prof->dasd_io_time2, factor);
    240	seq_printf(m, "Histogram of I/O time between ssch "
    241			    "and irq per sector\n");
    242	dasd_statistics_array(m, prof->dasd_io_time2ps, factor);
    243	seq_printf(m, "Histogram of I/O time between irq and end\n");
    244	dasd_statistics_array(m, prof->dasd_io_time3, factor);
    245	seq_printf(m, "# of req in chanq at enqueuing (1..32) \n");
    246	dasd_statistics_array(m, prof->dasd_io_nr_req, factor);
    247	spin_unlock_bh(&dasd_global_profile.lock);
    248#else
    249	seq_printf(m, "Statistics are not activated in this kernel\n");
    250#endif
    251	return 0;
    252}
    253
    254static int dasd_stats_proc_open(struct inode *inode, struct file *file)
    255{
    256	return single_open(file, dasd_stats_proc_show, NULL);
    257}
    258
    259static ssize_t dasd_stats_proc_write(struct file *file,
    260		const char __user *user_buf, size_t user_len, loff_t *pos)
    261{
    262#ifdef CONFIG_DASD_PROFILE
    263	char *buffer, *str;
    264	int rc;
    265
    266	if (user_len > 65536)
    267		user_len = 65536;
    268	buffer = dasd_get_user_string(user_buf, user_len);
    269	if (IS_ERR(buffer))
    270		return PTR_ERR(buffer);
    271
    272	/* check for valid verbs */
    273	str = skip_spaces(buffer);
    274	if (strncmp(str, "set", 3) == 0 && isspace(str[3])) {
    275		/* 'set xxx' was given */
    276		str = skip_spaces(str + 4);
    277		if (strcmp(str, "on") == 0) {
    278			/* switch on statistics profiling */
    279			rc = dasd_stats_all_block_on();
    280			if (rc) {
    281				dasd_stats_all_block_off();
    282				goto out_error;
    283			}
    284			rc = dasd_profile_on(&dasd_global_profile);
    285			if (rc) {
    286				dasd_stats_all_block_off();
    287				goto out_error;
    288			}
    289			dasd_profile_reset(&dasd_global_profile);
    290			dasd_global_profile_level = DASD_PROFILE_ON;
    291			pr_info("The statistics feature has been switched "
    292				"on\n");
    293		} else if (strcmp(str, "off") == 0) {
    294			/* switch off statistics profiling */
    295			dasd_global_profile_level = DASD_PROFILE_OFF;
    296			dasd_profile_off(&dasd_global_profile);
    297			dasd_stats_all_block_off();
    298			pr_info("The statistics feature has been switched "
    299				"off\n");
    300		} else
    301			goto out_parse_error;
    302	} else if (strncmp(str, "reset", 5) == 0) {
    303		/* reset the statistics */
    304		dasd_profile_reset(&dasd_global_profile);
    305		dasd_stats_all_block_reset();
    306		pr_info("The statistics have been reset\n");
    307	} else
    308		goto out_parse_error;
    309	vfree(buffer);
    310	return user_len;
    311out_parse_error:
    312	rc = -EINVAL;
    313	pr_warn("%s is not a supported value for /proc/dasd/statistics\n", str);
    314out_error:
    315	vfree(buffer);
    316	return rc;
    317#else
    318	pr_warn("/proc/dasd/statistics: is not activated in this kernel\n");
    319	return user_len;
    320#endif				/* CONFIG_DASD_PROFILE */
    321}
    322
    323static const struct proc_ops dasd_stats_proc_ops = {
    324	.proc_open	= dasd_stats_proc_open,
    325	.proc_read	= seq_read,
    326	.proc_lseek	= seq_lseek,
    327	.proc_release	= single_release,
    328	.proc_write	= dasd_stats_proc_write,
    329};
    330
    331/*
    332 * Create dasd proc-fs entries.
    333 * In case creation failed, cleanup and return -ENOENT.
    334 */
    335int
    336dasd_proc_init(void)
    337{
    338	dasd_proc_root_entry = proc_mkdir("dasd", NULL);
    339	if (!dasd_proc_root_entry)
    340		goto out_nodasd;
    341	dasd_devices_entry = proc_create_seq("devices", 0444,
    342					 dasd_proc_root_entry,
    343					 &dasd_devices_seq_ops);
    344	if (!dasd_devices_entry)
    345		goto out_nodevices;
    346	dasd_statistics_entry = proc_create("statistics",
    347					    S_IFREG | S_IRUGO | S_IWUSR,
    348					    dasd_proc_root_entry,
    349					    &dasd_stats_proc_ops);
    350	if (!dasd_statistics_entry)
    351		goto out_nostatistics;
    352	return 0;
    353
    354 out_nostatistics:
    355	remove_proc_entry("devices", dasd_proc_root_entry);
    356 out_nodevices:
    357	remove_proc_entry("dasd", NULL);
    358 out_nodasd:
    359	return -ENOENT;
    360}
    361
    362void
    363dasd_proc_exit(void)
    364{
    365	remove_proc_entry("devices", dasd_proc_root_entry);
    366	remove_proc_entry("statistics", dasd_proc_root_entry);
    367	remove_proc_entry("dasd", NULL);
    368}