brintos

brintos / linux-shallow public Read only

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