aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/freezer.c
diff options
context:
space:
mode:
authorBjoern B. Brandenburg <bbb@cs.unc.edu>2011-02-12 16:40:43 -0500
committerBjoern B. Brandenburg <bbb@cs.unc.edu>2011-04-12 21:39:15 -0400
commitfa08f1949dadd0cbc4dcf71eb11dede76a8ad2ad (patch)
tree2eb3a9e2afe8866f1e829e5e3a5ee2fda29cd0bf /kernel/freezer.c
parentc05eaa8091d2cadc20363d44a85ee454262f4bc2 (diff)
bugfix: release master CPU must signal task was pickedwip-release-master-fix
Otherwise, the release master CPU may try to reschedule in an infinite loop.
Diffstat (limited to 'kernel/freezer.c')
0 files changed, 0 insertions, 0 deletions
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
/*
 * 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.
 *
 */

#define KMSG_COMPONENT "dasd"

#include <linux/ctype.h>
#include <linux/string.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;

#ifdef CONFIG_DASD_PROFILE
static 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;
}
#endif /* CONFIG_DASD_PROFILE */

static int
dasd_devices_show(struct seq_file *m, void *v)
{
	struct dasd_device *device;
	struct dasd_block *block;
	char *substr;

	device = dasd_device_from_devindex((unsigned long) v - 1);
	if (IS_ERR(device))
		return 0;
	if (device->block)
		block = device->block;
	else {
		dasd_put_device(device);
		return 0;
	}
	/* Print device number. */
	seq_printf(m, "%s", dev_name(&device->cdev->dev));
	/* Print discipline string. */
	if (device != NULL && device->discipline != NULL)
		seq_printf(m, "(%s)", device->discipline->name);
	else
		seq_printf(m, "(none)");
	/* Print kdev. */
	if (block->gdp)
		seq_printf(m, " at (%3d:%6d)",
			   MAJOR(disk_devt(block->gdp)),
			   MINOR(disk_devt(block->gdp)));
	else
		seq_printf(m, "  at (???:??????)");
	/* Print device name. */
	if (block->gdp)
		seq_printf(m, " is %-8s", block->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_UNFMT:
		seq_printf(m, "unformatted");
		break;
	case DASD_STATE_READY:
	case DASD_STATE_ONLINE:
		seq_printf(m, "active ");
		if (dasd_check_blocksize(block->bp_block))
			seq_printf(m, "n/f	 ");
		else
			seq_printf(m,
				   "at blocksize: %d, %lld blocks, %lld MB",
				   block->bp_block, block->blocks,
				   ((block->bp_block >> 9) *
				    block->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 const 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 const struct file_operations dasd_devices_file_ops = {
	.owner		= THIS_MODULE,
	.open		= dasd_devices_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

static 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;
}

#ifdef CONFIG_DASD_PROFILE
static char *
dasd_statistics_array(char *str, unsigned int *array, int factor)
{
	int i;

	for (i = 0; i < 32; i++) {
		str += sprintf(str, "%7d ", array[i] / factor);
		if (i == 15)
			str += sprintf(str, "\n");
	}
	str += sprintf(str,"\n");
	return str;
}
#endif /* CONFIG_DASD_PROFILE */

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 factor;

	/* 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 counter 'overflow' on output */
	for (factor = 1; (prof->dasd_io_reqs / factor) > 9999999;
	     factor *= 10);

	str = page;
	str += sprintf(str, "%d dasd I/O requests\n", prof->dasd_io_reqs);
	str += sprintf(str, "with %u sectors(512B each)\n",
		       prof->dasd_io_sects);
	str += sprintf(str, "Scale Factor is  %d\n", factor);
	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, factor);
	str += sprintf(str, "Histogram of I/O times (microseconds)\n");
	str = dasd_statistics_array(str, prof->dasd_io_times, factor);
	str += sprintf(str, "Histogram of I/O times per sector\n");
	str = dasd_statistics_array(str, prof->dasd_io_timps, factor);
	str += sprintf(str, "Histogram of I/O time till ssch\n");
	str = dasd_statistics_array(str, prof->dasd_io_time1, factor);
	str += sprintf(str, "Histogram of I/O time between ssch and irq\n");
	str = dasd_statistics_array(str, prof->dasd_io_time2, factor);
	str += sprintf(str, "Histogram of I/O time between ssch "
			    "and irq per sector\n");
	str = dasd_statistics_array(str, prof->dasd_io_time2ps, factor);
	str += sprintf(str, "Histogram of I/O time between irq and end\n");
	str = dasd_statistics_array(str, prof->dasd_io_time3, factor);
	str += sprintf(str, "# of req in chanq at enqueuing (1..32) \n");
	str = dasd_statistics_array(str, prof->dasd_io_nr_req, factor);