mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Initial s390-tools-2.0.0 import
This commit is based on the s390-tools-1.39.0 version. Changes on top of s390-tools-1.39.0: - Add MIT license to all source files - Add LICENSE file - Transform REAMDE to README.md (markdown) - Add AUTHORS.md file - Add CONTRIBUTING.md file - Move changelog from README to CHANGELOG.md file Reviewed-by: Stefan Haberland <sth@linux.vnet.ibm.com> Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
include ../../common.mak
|
||||
|
||||
ALL_CPPFLAGS += -I../include -I../boot
|
||||
|
||||
libs = $(rootdir)/libdasd/libdasd.a \
|
||||
$(rootdir)/libu2s/libu2s.a \
|
||||
$(rootdir)/libutil/libutil.a
|
||||
|
||||
all: tunedasd
|
||||
|
||||
|
||||
objects = tunedasd.o disk.o
|
||||
|
||||
tunedasd: $(objects) $(libs)
|
||||
|
||||
install: all
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR)
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 tunedasd $(DESTDIR)$(BINDIR)
|
||||
|
||||
clean:
|
||||
rm -f *.o tunedasd
|
||||
|
||||
.PHONY: all install clean
|
||||
@@ -0,0 +1,719 @@
|
||||
/*
|
||||
* tunedasd - Adjust tunable parameters on DASD devices
|
||||
*
|
||||
* Functions to handle DASD-IOCTLs
|
||||
*
|
||||
* Copyright IBM Corp. 2004, 2017
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "lib/dasd_sys.h"
|
||||
|
||||
#include "disk.h"
|
||||
#include "tunedasd.h"
|
||||
|
||||
#define BUS_ID_SIZE 30
|
||||
|
||||
/*
|
||||
* DASD DEFINITIONS (copied from dasd.h)
|
||||
*/
|
||||
|
||||
#define DASD_IOCTL_LETTER 'D'
|
||||
|
||||
/*
|
||||
* struct profile_info_t
|
||||
* holds the profiling information
|
||||
*/
|
||||
typedef struct dasd_profile_info_t {
|
||||
unsigned int dasd_io_reqs; /* # of requests processed at all */
|
||||
unsigned int dasd_io_sects; /* # of sectors processed at all */
|
||||
unsigned int dasd_io_secs[32]; /* request's sizes */
|
||||
unsigned int dasd_io_times[32]; /* requests's times */
|
||||
unsigned int dasd_io_timps[32]; /* requests's times per sector */
|
||||
unsigned int dasd_io_time1[32]; /* time from build to start */
|
||||
unsigned int dasd_io_time2[32]; /* time from start to irq */
|
||||
unsigned int dasd_io_time2ps[32]; /*time from start to irq */
|
||||
unsigned int dasd_io_time3[32]; /* time from irq to end */
|
||||
unsigned int dasd_io_nr_req[32]; /* # of requests in chanq */
|
||||
} dasd_profile_info_t;
|
||||
|
||||
|
||||
/*
|
||||
* struct attrib_data_t
|
||||
* represents the operation (cache) bits for the device.
|
||||
* Used in DE to influence caching of the DASD.
|
||||
*/
|
||||
typedef struct attrib_data_t {
|
||||
unsigned char operation:3; /* cache operation mode */
|
||||
unsigned char reserved:5;
|
||||
unsigned short nr_cyl; /* no of cyliners for read ahaed */
|
||||
unsigned char reserved2[29]; /* for future use */
|
||||
} __attribute__ ((packed)) attrib_data_t;
|
||||
|
||||
/* definition of operation (cache) bits within attributes of DE */
|
||||
#define DASD_NORMAL_CACHE 0x0
|
||||
#define DASD_BYPASS_CACHE 0x1
|
||||
#define DASD_INHIBIT_LOAD 0x2
|
||||
#define DASD_SEQ_ACCESS 0x3
|
||||
#define DASD_SEQ_PRESTAGE 0x4
|
||||
#define DASD_REC_ACCESS 0x5
|
||||
|
||||
/*
|
||||
* Data returned by Sense Path Group ID (SNID)
|
||||
*/
|
||||
struct dasd_snid_data {
|
||||
struct {
|
||||
__u8 group:2;
|
||||
__u8 reserve:2;
|
||||
__u8 mode:1;
|
||||
__u8 res:3;
|
||||
} __attribute__ ((packed)) path_state;
|
||||
__u8 pgid[11];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct dasd_snid_ioctl_data {
|
||||
struct dasd_snid_data data;
|
||||
__u8 path_mask;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
/*
|
||||
* DASD-IOCTLs (copied from dasd.h)
|
||||
*/
|
||||
/* Issue a reserve/release command, rsp. */
|
||||
#define BIODASDRSRV _IO (DASD_IOCTL_LETTER,2) /* reserve */
|
||||
#define BIODASDRLSE _IO (DASD_IOCTL_LETTER,3) /* release */
|
||||
#define BIODASDSLCK _IO (DASD_IOCTL_LETTER,4) /* steal lock */
|
||||
/* reset profiling information of a device */
|
||||
#define BIODASDPRRST _IO (DASD_IOCTL_LETTER,5)
|
||||
|
||||
/* retrieve profiling information of a device */
|
||||
#define BIODASDPRRD _IOR (DASD_IOCTL_LETTER,2,dasd_profile_info_t)
|
||||
/* Get Attributes (cache operations) */
|
||||
#define BIODASDGATTR _IOR(DASD_IOCTL_LETTER,5,attrib_data_t)
|
||||
|
||||
/* Set Attributes (cache operations) */
|
||||
#define BIODASDSATTR _IOW (DASD_IOCTL_LETTER,2,attrib_data_t)
|
||||
|
||||
/* Get Sense Path Group ID (SNID) data */
|
||||
#define BIODASDSNID _IOWR(DASD_IOCTL_LETTER, 1, struct dasd_snid_ioctl_data)
|
||||
|
||||
|
||||
/* id definition for profile items */
|
||||
enum prof_id {
|
||||
prof_reqs = 0,
|
||||
prof_sects = 1,
|
||||
prof_sizes = 2,
|
||||
prof_total = 3,
|
||||
prof_totsect = 4,
|
||||
prof_start = 5,
|
||||
prof_irq = 6,
|
||||
prof_irqsect = 7,
|
||||
prof_end = 8,
|
||||
prof_queue = 9
|
||||
};
|
||||
|
||||
/* Mapping for caching modes */
|
||||
static struct {
|
||||
char* mode;
|
||||
int id;
|
||||
} mode_list[] = {
|
||||
{ "normal", DASD_NORMAL_CACHE },
|
||||
{ "bypass", DASD_BYPASS_CACHE },
|
||||
{ "inhibit", DASD_INHIBIT_LOAD },
|
||||
{ "sequential", DASD_SEQ_ACCESS },
|
||||
{ "prestage", DASD_SEQ_PRESTAGE },
|
||||
{ "record", DASD_REC_ACCESS }
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Check for valid cache parameters.
|
||||
*/
|
||||
int
|
||||
check_cache (char* cache)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
/* Check for valid parameters */
|
||||
for (i = 0; i < sizeof(mode_list)/sizeof(mode_list[0]); i++) {
|
||||
if (!strcmp (cache, mode_list[i].mode)) {
|
||||
return mode_list[i].id;
|
||||
}
|
||||
}
|
||||
error_print ("Invalid caching mode '%s' given", cache);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve name of cache mode identified by number.
|
||||
*/
|
||||
static char *get_cache_name(int id)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < sizeof (mode_list) / sizeof (mode_list[0]);
|
||||
i++) {
|
||||
if (id == mode_list[i].id) {
|
||||
return mode_list[i].mode;
|
||||
}
|
||||
}
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check for valid number of cylinders.
|
||||
*/
|
||||
int
|
||||
check_no_cyl (char* no_cyl)
|
||||
{
|
||||
int nr_cyl;
|
||||
char* err_ptr;
|
||||
if (!no_cyl) {
|
||||
/* set default = 2 Cylinders - if option is missing */
|
||||
return 2;
|
||||
} else {
|
||||
err_ptr = NULL;
|
||||
nr_cyl = strtoul (no_cyl, &err_ptr, 0);
|
||||
|
||||
if ((errno) ||
|
||||
(*err_ptr != '\0')) {
|
||||
error_print ("Invalid number of cylinders given '%s'",
|
||||
no_cyl);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return nr_cyl;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check for valid profile item parameters.
|
||||
*/
|
||||
int
|
||||
check_prof_item (char* prof_item)
|
||||
{
|
||||
/* Mapping for profile items */
|
||||
static struct {
|
||||
char* item;
|
||||
int id;
|
||||
} prof_list[] = {
|
||||
{ "reqs", prof_reqs },
|
||||
{ "sects", prof_sects },
|
||||
{ "sizes", prof_sizes },
|
||||
{ "total", prof_total },
|
||||
{ "totsect", prof_totsect },
|
||||
{ "start", prof_start },
|
||||
{ "irq", prof_irq },
|
||||
{ "irqsect", prof_irqsect },
|
||||
{ "end", prof_end },
|
||||
{ "queue", prof_queue }
|
||||
};
|
||||
|
||||
unsigned int i;
|
||||
|
||||
/* Check for valid parameters */
|
||||
for (i = 0; i < sizeof(prof_list)/sizeof(prof_list[0]); i++) {
|
||||
if (!strcmp (prof_item, prof_list[i].item)) {
|
||||
return prof_list[i].id;
|
||||
}
|
||||
}
|
||||
error_print ("Invalid profile item '%s' given", prof_item);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get the caching algorithm used for the channel programs of this device.
|
||||
* 'cache' is the caching mode (see ESS docu for more info) and 'no_cyl'
|
||||
* the number of cylinders to be cached.
|
||||
*/
|
||||
int
|
||||
disk_get_cache (char* device)
|
||||
{
|
||||
int fd;
|
||||
attrib_data_t attrib_data;
|
||||
|
||||
/* Open device file */
|
||||
fd = open (device, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
error_print ("<%s> - %s", device, strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get the given caching attributes */
|
||||
if (ioctl (fd, BIODASDGATTR, &attrib_data)) {
|
||||
error_print ("Could not get cache attributes for device <%s>",
|
||||
device);
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf ("%s (%i cyl)\n",
|
||||
get_cache_name(attrib_data.operation),
|
||||
attrib_data.nr_cyl);
|
||||
|
||||
close (fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set the caching algorithm used for the channel programs of this device.
|
||||
* 'cache' is the caching mode (see ESS docu for more info) and 'no_cyl'
|
||||
* the number of cylinders to be cached.
|
||||
*/
|
||||
int
|
||||
disk_set_cache (char* device, char* cache, char* no_cyl)
|
||||
{
|
||||
int fd;
|
||||
attrib_data_t attrib_data;
|
||||
|
||||
/* get caching mode and # cylinders */
|
||||
attrib_data.operation = check_cache (cache);
|
||||
attrib_data.nr_cyl = check_no_cyl (no_cyl);
|
||||
|
||||
if (attrib_data.nr_cyl > 40) {
|
||||
printf ("WARNING: This is a very large number of "
|
||||
"cylinders ;) %i\n",
|
||||
attrib_data.nr_cyl);
|
||||
}
|
||||
|
||||
/* Open device file */
|
||||
fd = open (device, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
error_print ("<%s> - %s", device, strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set the given caching attributes */
|
||||
printf ("Setting cache mode for device <%s>...\n", device);
|
||||
if (ioctl (fd, BIODASDSATTR, &attrib_data)) {
|
||||
error_print ("Could not set caching for device <%s>", device);
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf ("Done.\n");
|
||||
close (fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Reserve the device.
|
||||
*/
|
||||
int
|
||||
disk_reserve (char* device)
|
||||
{
|
||||
int fd;
|
||||
|
||||
/* Open device file */
|
||||
fd = open (device, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
error_print ("<%s> - %s", device, strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Reserve device */
|
||||
printf ("Reserving device <%s>...\n", device);
|
||||
if (ioctl (fd, BIODASDRSRV)) {
|
||||
error_print ("Could not reserve device <%s>", device);
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf ("Done.\n");
|
||||
close (fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Release the device.
|
||||
*/
|
||||
int
|
||||
disk_release (char* device)
|
||||
{
|
||||
int fd;
|
||||
|
||||
/* Open device file */
|
||||
fd = open (device, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
error_print ("<%s> - %s", device, strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Release device */
|
||||
printf ("Releasing device <%s>...\n", device);
|
||||
if (ioctl (fd, BIODASDRLSE)) {
|
||||
error_print ("Could not release device <%s>", device);
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf ("Done.\n");
|
||||
close (fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Unconditional reserve the device.
|
||||
* This means to reserve the device even if it was already reserved.
|
||||
* The current reserve is broken (steal lock).
|
||||
*/
|
||||
int
|
||||
disk_slock (char* device)
|
||||
{
|
||||
int fd;
|
||||
|
||||
/* Open device file */
|
||||
fd = open (device, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
error_print ("<%s> - %s", device, strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Unconditional reserve device */
|
||||
printf ("Unconditional reserving device <%s>...\n", device);
|
||||
if (ioctl (fd, BIODASDSLCK)) {
|
||||
error_print ("Could not unconditional reserve device <%s>",
|
||||
device);
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf ("Done.\n");
|
||||
close (fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Uses the Sense Path Group ID (SNID) ioctl to find out if
|
||||
* a device is reserved to it's path group.
|
||||
*/
|
||||
int
|
||||
disk_query_reserve_status(char* device)
|
||||
{
|
||||
int fd;
|
||||
struct dasd_snid_ioctl_data snid;
|
||||
|
||||
/* Open device file */
|
||||
fd = open (device, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
error_print ("<%s> - %s", device, strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
snid.path_mask = 0;
|
||||
/* Release device */
|
||||
if (ioctl(fd, BIODASDSNID, &snid)) {
|
||||
error_print("Could not read reserve status"
|
||||
" for device <%s>", device);
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
switch (snid.data.path_state.reserve) {
|
||||
case 0:
|
||||
printf("none\n");
|
||||
break;
|
||||
case 1:
|
||||
printf("implicit\n");
|
||||
break;
|
||||
case 2:
|
||||
printf("other\n");
|
||||
break;
|
||||
case 3:
|
||||
printf("reserved\n");
|
||||
break;
|
||||
}
|
||||
close (fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int disk_profile_summary(dasd_profile_info_t dasd_profile_info)
|
||||
{
|
||||
int factor, i;
|
||||
|
||||
/* prevent counter 'overflow' on output */
|
||||
for (factor = 1; (dasd_profile_info.dasd_io_reqs / factor) > 9999999;
|
||||
factor *= 10) ;
|
||||
/* print the profile info */
|
||||
printf("\n%d dasd I/O requests\n", dasd_profile_info.dasd_io_reqs);
|
||||
printf("with %u sectors(512B each)\n",
|
||||
dasd_profile_info.dasd_io_sects);
|
||||
printf("Scale factor is %d \n\n", factor);
|
||||
|
||||
printf(" __<4 ___8 __16 __32 __64 "
|
||||
" _128 _256 _512 __1k __2k "
|
||||
" __4k __8k _16k _32k _64k "
|
||||
" 128k\n");
|
||||
|
||||
printf(" _256 _512 __1M __2M __4M "
|
||||
" __8M _16M _32M _64M 128M "
|
||||
" 256M 512M __1G __2G __4G "
|
||||
" _>4G\n");
|
||||
|
||||
printf("Histogram of sizes (512B secs)\n");
|
||||
for (i = 0; i < 16; i++) {
|
||||
printf("%7d ", dasd_profile_info.dasd_io_secs[i] / factor);
|
||||
}
|
||||
printf("\n");
|
||||
for (; i < 32; i++) {
|
||||
printf("%7d ", dasd_profile_info.dasd_io_secs[i] / factor);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("Histogram of I/O times (microseconds)\n");
|
||||
for (i = 0; i < 16; i++) {
|
||||
printf("%7d ", dasd_profile_info.dasd_io_times[i] / factor);
|
||||
}
|
||||
printf("\n");
|
||||
for (; i < 32; i++) {
|
||||
printf("%7d ", dasd_profile_info.dasd_io_times[i] / factor);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("Histogram of I/O times per sector\n");
|
||||
for (i = 0; i < 16; i++) {
|
||||
printf("%7d ", dasd_profile_info.dasd_io_timps[i] / factor);
|
||||
}
|
||||
printf("\n");
|
||||
for (; i < 32; i++) {
|
||||
printf("%7d ", dasd_profile_info.dasd_io_timps[i] / factor);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("Histogram of I/O time till ssch\n");
|
||||
for (i = 0; i < 16; i++) {
|
||||
printf("%7d ", dasd_profile_info.dasd_io_time1[i] / factor);
|
||||
}
|
||||
printf("\n");
|
||||
for (; i < 32; i++) {
|
||||
printf("%7d ", dasd_profile_info.dasd_io_time1[i] / factor);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("Histogram of I/O time between ssch and irq\n");
|
||||
for (i = 0; i < 16; i++) {
|
||||
printf("%7d ", dasd_profile_info.dasd_io_time2[i] / factor);
|
||||
}
|
||||
printf("\n");
|
||||
for (; i < 32; i++) {
|
||||
printf("%7d ", dasd_profile_info.dasd_io_time2[i] / factor);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("Histogram of I/O time between ssch and irq per "
|
||||
"sector\n");
|
||||
for (i = 0; i < 16; i++) {
|
||||
printf("%7d ", dasd_profile_info.dasd_io_time2ps[i] / factor);
|
||||
}
|
||||
printf("\n");
|
||||
for (; i < 32; i++) {
|
||||
printf("%7d ", dasd_profile_info.dasd_io_time2ps[i] / factor);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("Histogram of I/O time between irq and end\n");
|
||||
for (i = 0; i < 16; i++) {
|
||||
printf("%7d ", dasd_profile_info.dasd_io_time3[i] / factor);
|
||||
}
|
||||
printf("\n");
|
||||
for (; i < 32; i++) {
|
||||
printf("%7d ", dasd_profile_info.dasd_io_time3[i] / factor);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("# of req in chanq at enqueuing (1..32) \n");
|
||||
for (i = 0; i < 16; i++) {
|
||||
printf("%7d ", dasd_profile_info.dasd_io_nr_req[i] / factor);
|
||||
}
|
||||
printf("\n");
|
||||
for (; i < 32; i++) {
|
||||
printf("%7d ", dasd_profile_info.dasd_io_nr_req[i] / factor);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int disk_profile_item(dasd_profile_info_t dasd_profile_info,
|
||||
char *prof_item)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Check for given profile item*/
|
||||
switch (check_prof_item (prof_item)) {
|
||||
case prof_reqs:
|
||||
printf ("%d", dasd_profile_info.dasd_io_reqs);
|
||||
break;
|
||||
case prof_sects:
|
||||
printf ("%d", dasd_profile_info.dasd_io_sects);
|
||||
break;
|
||||
case prof_sizes:
|
||||
for (i = 0; i < 32; i++) {
|
||||
printf ("%10d|", dasd_profile_info.dasd_io_secs[i]);
|
||||
}
|
||||
break;
|
||||
case prof_total:
|
||||
for (i = 0; i < 32; i++) {
|
||||
printf ("%10d|", dasd_profile_info.dasd_io_times[i]);
|
||||
}
|
||||
break;
|
||||
case prof_totsect:
|
||||
for (i = 0; i < 32; i++) {
|
||||
printf ("%10d|", dasd_profile_info.dasd_io_timps[i]);
|
||||
}
|
||||
break;
|
||||
case prof_start:
|
||||
for (i = 0; i < 32; i++) {
|
||||
printf ("%10d|", dasd_profile_info.dasd_io_time1[i]);
|
||||
}
|
||||
break;
|
||||
case prof_irq:
|
||||
for (i = 0; i < 32; i++) {
|
||||
printf ("%10d|", dasd_profile_info.dasd_io_time2[i]);
|
||||
}
|
||||
break;
|
||||
case prof_irqsect:
|
||||
for (i = 0; i < 32; i++) {
|
||||
printf ("%10d|", dasd_profile_info.dasd_io_time2ps[i]);
|
||||
}
|
||||
break;
|
||||
case prof_end:
|
||||
for (i = 0; i < 32; i++) {
|
||||
printf ("%10d|", dasd_profile_info.dasd_io_time3[i]);
|
||||
}
|
||||
break;
|
||||
case prof_queue:
|
||||
for (i = 0; i < 32; i++) {
|
||||
printf ("%10d|", dasd_profile_info.dasd_io_nr_req[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
printf ("\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get and print the profiling info of the device.
|
||||
*/
|
||||
int
|
||||
disk_profile (char* device, char* prof_item)
|
||||
{
|
||||
int fd, rc;
|
||||
dasd_profile_info_t dasd_profile_info;
|
||||
|
||||
/* Open device file */
|
||||
fd = open (device, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
error_print ("<%s> - %s", device, strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get the profile info */
|
||||
if (ioctl (fd, BIODASDPRRD, &dasd_profile_info)) {
|
||||
switch (errno) {
|
||||
case EIO: /* profiling is not active */
|
||||
error_print ("Profiling (on device <%s>) is not "
|
||||
"active.", device);
|
||||
break;
|
||||
default: /* all other errors */
|
||||
error_print ("Could not get profile info for device "
|
||||
"<%s>.", device);
|
||||
}
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
/* Check for profile item or summary */
|
||||
if (!prof_item) {
|
||||
rc = disk_profile_summary (dasd_profile_info);
|
||||
} else {
|
||||
rc = disk_profile_item (dasd_profile_info, prof_item);
|
||||
}
|
||||
|
||||
close (fd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Reset the profiling counters of the device.
|
||||
*/
|
||||
int
|
||||
disk_reset_prof (char* device)
|
||||
{
|
||||
int fd;
|
||||
|
||||
/* Open device file */
|
||||
fd = open (device, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
error_print ("<%s> - %s", device, strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* reset profile info */
|
||||
printf ("Resetting profile info for device <%s>...\n", device);
|
||||
if (ioctl (fd, BIODASDPRRST)) {
|
||||
error_print ("Could not reset profile info for device <%s>",
|
||||
device);
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf ("Done.\n");
|
||||
close (fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int disk_reset_chpid(char *device, char *chpid)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (chpid)
|
||||
printf("Resetting chpid %s for device <%s>...\n", chpid,
|
||||
device);
|
||||
else
|
||||
printf("Resetting all chpids for device <%s>...\n", device);
|
||||
|
||||
rc = dasd_reset_chpid(device, chpid);
|
||||
switch (rc) {
|
||||
case 0:
|
||||
printf("Done.\n");
|
||||
return 0;
|
||||
case ENODEV:
|
||||
error_print("%s: %s", device, strerror(errno));
|
||||
break;
|
||||
case EINVAL:
|
||||
error_print("%s: Could not reset chpid %s: Invalid CHPID",
|
||||
device, chpid);
|
||||
break;
|
||||
case ENOENT:
|
||||
error_print("%s: Could not reset chpid %s: CHPID not defined for device",
|
||||
device, chpid);
|
||||
break;
|
||||
default:
|
||||
error_print("%s: Could not reset chpid %s",
|
||||
device, chpid);
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -0,0 +1,598 @@
|
||||
/*
|
||||
* tunedasd - Adjust tunable parameters on DASD devices
|
||||
*
|
||||
* Copyright IBM Corp. 2004, 2017
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "lib/util_file.h"
|
||||
#include "lib/util_opt.h"
|
||||
#include "lib/util_prg.h"
|
||||
#include "lib/zt_common.h"
|
||||
|
||||
#include "disk.h"
|
||||
#include "error.h"
|
||||
#include "tunedasd.h"
|
||||
|
||||
static const struct util_prg prg = {
|
||||
.desc = "Adjust tunable DASD parameters. More than one DEVICE node can "
|
||||
"be specified, but at least one (e.g. /dev/dasda)",
|
||||
.args = "DEVICE1 [DEVICE2...]",
|
||||
.copyright_vec = {
|
||||
{
|
||||
.owner = "IBM Corp.",
|
||||
.pub_first = 1999,
|
||||
.pub_last = 2006,
|
||||
},
|
||||
UTIL_PRG_COPYRIGHT_END
|
||||
}
|
||||
};
|
||||
|
||||
/* Defines for options with no short command */
|
||||
#define OPT_PATH_RESET_ALL 128
|
||||
#define OPT_ENABLE_STATS 129
|
||||
#define OPT_DISABLE_STATS 130
|
||||
|
||||
static struct util_opt opt_vec[] = {
|
||||
UTIL_OPT_SECTION("CACHING MODES (ECKD ONLY)"),
|
||||
{
|
||||
.option = { "cache", required_argument, NULL, 'c' },
|
||||
.argument = "BEHAVIOUR",
|
||||
.desc = "Specify caching behaviour on storage server: "
|
||||
"normal, bypass, inhibit, sequential, prestage, or record",
|
||||
},
|
||||
{
|
||||
.option = { "no_cyl", required_argument, NULL, 'n' },
|
||||
.argument = "NUM",
|
||||
.desc = "NUM cylinders to be cached (only valid with -c/--cache)",
|
||||
},
|
||||
{
|
||||
.option = { "get_cache", no_argument, NULL, 'g' },
|
||||
.desc = "Get current storage server caching behaviour",
|
||||
},
|
||||
UTIL_OPT_SECTION("RESERVE / RELEASE"),
|
||||
{
|
||||
.option = { "release", no_argument, NULL, 'L' },
|
||||
.desc = "Release device",
|
||||
},
|
||||
{
|
||||
.option = { "slock", no_argument, NULL, 'O' },
|
||||
.desc = "Unconditional reservce device\n"
|
||||
"NOTE: Use with care, this breaks an existing lock",
|
||||
},
|
||||
{
|
||||
.option = { "query_reserve", no_argument, NULL, 'Q' },
|
||||
.desc = "Print reserve status of device",
|
||||
},
|
||||
{
|
||||
.option = { "reserve", no_argument, NULL, 'S' },
|
||||
.desc = "Reserve device",
|
||||
},
|
||||
UTIL_OPT_SECTION("PERFORMANCE STATISTICS"),
|
||||
{
|
||||
.option = {
|
||||
"enable-stats", no_argument, NULL, OPT_ENABLE_STATS
|
||||
},
|
||||
.desc = "Enable performance statistics globally",
|
||||
.flags = UTIL_OPT_FLAG_NOSHORT,
|
||||
},
|
||||
{
|
||||
.option = {
|
||||
"disable-stats", no_argument, NULL, OPT_DISABLE_STATS
|
||||
},
|
||||
.desc = "Disable performance statistics globally",
|
||||
.flags = UTIL_OPT_FLAG_NOSHORT,
|
||||
},
|
||||
{
|
||||
.option = { "prof_item", required_argument, NULL, 'I' },
|
||||
.argument = "ROW",
|
||||
.desc = "Print single profile item: reqs, sects, sizes, total, "
|
||||
"totsect, start, irq, irqsect, end, or queue",
|
||||
},
|
||||
{
|
||||
.option = { "profile", no_argument, NULL, 'P' },
|
||||
.desc = "Print profile info of device",
|
||||
},
|
||||
{
|
||||
.option = { "reset_prof", no_argument, NULL, 'R' },
|
||||
.desc = "Reset profile info of device",
|
||||
},
|
||||
UTIL_OPT_SECTION("MISC"),
|
||||
{
|
||||
.option = { "path_reset", required_argument, NULL, 'p' },
|
||||
.argument = "CHPID",
|
||||
.desc = "Reset channel path CHPID of a device",
|
||||
},
|
||||
{
|
||||
.option = {
|
||||
"path_reset_all", no_argument, NULL, OPT_PATH_RESET_ALL
|
||||
},
|
||||
.desc = "Reset all channel paths of a device",
|
||||
.flags = UTIL_OPT_FLAG_NOSHORT,
|
||||
},
|
||||
UTIL_OPT_HELP,
|
||||
UTIL_OPT_VERSION,
|
||||
UTIL_OPT_END
|
||||
};
|
||||
|
||||
#define CMD_KEYWORD_NUM 16
|
||||
#define DEVICES_NUM 256
|
||||
|
||||
enum cmd_keyword_id {
|
||||
cmd_keyword_help,
|
||||
cmd_keyword_version,
|
||||
cmd_keyword_get_cache,
|
||||
cmd_keyword_cache,
|
||||
cmd_keyword_no_cyl,
|
||||
cmd_keyword_reserve,
|
||||
cmd_keyword_release,
|
||||
cmd_keyword_slock,
|
||||
cmd_keyword_profile,
|
||||
cmd_keyword_prof_item,
|
||||
cmd_keyword_reset_prof,
|
||||
cmd_keyword_query_reserve,
|
||||
cmd_keyword_path,
|
||||
cmd_keyword_path_all,
|
||||
cmd_keyword_enable_stats,
|
||||
cmd_keyword_disable_stats,
|
||||
};
|
||||
|
||||
|
||||
/* Mapping of keyword IDs to strings */
|
||||
static const struct {
|
||||
char* keyword;
|
||||
enum cmd_keyword_id id;
|
||||
} keyword_list[] = {
|
||||
{ "help", cmd_keyword_help },
|
||||
{ "version", cmd_keyword_version },
|
||||
{ "get_cache", cmd_keyword_get_cache },
|
||||
{ "cache", cmd_keyword_cache },
|
||||
{ "no_cyl", cmd_keyword_no_cyl },
|
||||
{ "reserve", cmd_keyword_reserve },
|
||||
{ "release", cmd_keyword_release },
|
||||
{ "slock", cmd_keyword_slock },
|
||||
{ "profile", cmd_keyword_profile },
|
||||
{ "prof_item", cmd_keyword_prof_item },
|
||||
{ "reset_prof", cmd_keyword_reset_prof },
|
||||
{ "query_reserve", cmd_keyword_query_reserve },
|
||||
{ "path_reset", cmd_keyword_path },
|
||||
{ "path_reset_all", cmd_keyword_path_all },
|
||||
{ "enable-stats", cmd_keyword_enable_stats },
|
||||
{ "disable-stats", cmd_keyword_disable_stats }
|
||||
};
|
||||
|
||||
|
||||
enum cmd_key_state {
|
||||
req, /* Keyword is required */
|
||||
opt, /* Keyword is optional */
|
||||
inv /* Keyword is invalid */
|
||||
};
|
||||
|
||||
|
||||
/* Determines which combination of keywords are valid */
|
||||
static enum cmd_key_state cmd_key_table[CMD_KEYWORD_NUM][CMD_KEYWORD_NUM] = {
|
||||
/* help vers get_ cach no_c rese rele sloc prof prof rese quer path path
|
||||
* ion cach e yl rve ase k ile _ite t_pr y_re _all
|
||||
* e m of serv
|
||||
*/
|
||||
/* help */ { req, opt, opt, opt, opt, opt, opt, opt, opt, opt, opt, inv, inv, inv, inv, inv },
|
||||
/* version */ { inv, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
|
||||
/* get_cache */ { opt, opt, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
|
||||
/* cache */ { opt, opt, inv, req, opt, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
|
||||
/* no_cyl */ { opt, opt, inv, req, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
|
||||
/* reserve */ { opt, opt, inv, inv, inv, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
|
||||
/* release */ { opt, opt, inv, inv, inv, inv, req, inv, inv, inv, inv, inv, inv, inv, inv, inv },
|
||||
/* slock */ { opt, opt, inv, inv, inv, inv, inv, req, inv, inv, inv, inv, inv, inv, inv, inv },
|
||||
/* profile */ { opt, opt, inv, inv, inv, inv, inv, inv, req, opt, inv, inv, inv, inv, inv, inv },
|
||||
/* prof_item */ { opt, opt, inv, inv, inv, inv, inv, inv, req, req, inv, inv, inv, inv, inv, inv },
|
||||
/* reset_prof */ { opt, opt, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv, inv, inv, inv },
|
||||
/* query_reserve */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv, inv, inv },
|
||||
/* path */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv, inv },
|
||||
/* path_all */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv },
|
||||
/* enable-stats */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv },
|
||||
/* disable-stats */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req },
|
||||
};
|
||||
|
||||
struct parameter {
|
||||
int kw_given;
|
||||
char *data;
|
||||
};
|
||||
|
||||
struct command_line {
|
||||
struct parameter parm[CMD_KEYWORD_NUM];
|
||||
char * devices[DEVICES_NUM];
|
||||
int device_id;
|
||||
};
|
||||
|
||||
/* Error message string */
|
||||
#define ERROR_STRING_SIZE 1024
|
||||
static char error_string[ERROR_STRING_SIZE];
|
||||
|
||||
|
||||
/*
|
||||
* Generate and print an error message based on the formatted
|
||||
* text string FMT and a variable amount of extra arguments.
|
||||
*/
|
||||
void
|
||||
error_print (const char* fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start (args, fmt);
|
||||
vsnprintf (error_string, ERROR_STRING_SIZE, fmt, args);
|
||||
va_end (args);
|
||||
|
||||
fprintf (stderr, "Error: %s\n", error_string);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Print usage information.
|
||||
*/
|
||||
static void print_usage(void)
|
||||
{
|
||||
util_prg_print_help();
|
||||
util_opt_print_help();
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether calling user is root. Return 0 if user is root, non-zero
|
||||
* otherwise.
|
||||
*/
|
||||
static int
|
||||
check_for_root (void)
|
||||
{
|
||||
if (geteuid () != 0) {
|
||||
error_print ("Must be root to perform this operation");
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Retrieve name of keyword identified by ID.
|
||||
*/
|
||||
static char *get_keyword_name(enum cmd_keyword_id id)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < sizeof (keyword_list) / sizeof (keyword_list[0]);
|
||||
i++) {
|
||||
if (id == keyword_list[i].id) {
|
||||
return keyword_list[i].keyword;
|
||||
}
|
||||
}
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check the given function for given options and valid combinations of
|
||||
* options
|
||||
*/
|
||||
static int check_key_state(struct command_line *cmdline)
|
||||
{
|
||||
int i,j;
|
||||
|
||||
/* Find first given keyword */
|
||||
for (i = 0; i < CMD_KEYWORD_NUM && !cmdline->parm[i].kw_given; i++);
|
||||
|
||||
if (i >= CMD_KEYWORD_NUM) {
|
||||
error_print ("No valid parameter specified");
|
||||
print_usage ();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check keywords */
|
||||
for (j = 0; j < CMD_KEYWORD_NUM; j++) {
|
||||
|
||||
switch (cmd_key_table[i][j]) {
|
||||
case req:
|
||||
/* Missing keyword on command line */
|
||||
if (!(cmdline->parm[j].kw_given)) {
|
||||
error_print ("Option '%s' required when "
|
||||
"specifying '%s'",
|
||||
get_keyword_name (j),
|
||||
get_keyword_name (i));
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case inv:
|
||||
/* Invalid keyword on command line */
|
||||
if (cmdline->parm[j].kw_given) {
|
||||
error_print ("Only one of options '%s' and "
|
||||
"'%s' allowed",
|
||||
get_keyword_name (i),
|
||||
get_keyword_name (j));
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case opt:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Save the given command together with its parameter.
|
||||
*/
|
||||
static int
|
||||
store_option (struct command_line* cmdline, enum cmd_keyword_id keyword,
|
||||
char* value)
|
||||
{
|
||||
if ((cmdline->parm[(int) keyword]).kw_given) {
|
||||
error_print ("Option '%s' specified more than once",
|
||||
get_keyword_name (keyword));
|
||||
return -1;
|
||||
}
|
||||
cmdline->parm[(int) keyword].kw_given = 1;
|
||||
cmdline->parm[(int) keyword].data = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Parse the command line for valid parameters.
|
||||
*/
|
||||
static int get_command_line(int argc, char *argv[], struct command_line *line)
|
||||
{
|
||||
struct command_line cmdline;
|
||||
int opt;
|
||||
int rc;
|
||||
|
||||
util_prg_init(&prg);
|
||||
util_opt_init(opt_vec, NULL);
|
||||
|
||||
memset ((void *) &cmdline, 0, sizeof (struct command_line));
|
||||
|
||||
/* Process options */
|
||||
do {
|
||||
opt = util_opt_getopt_long(argc, argv);
|
||||
|
||||
rc = 0;
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
rc = store_option (&cmdline, cmd_keyword_help,
|
||||
optarg);
|
||||
break;
|
||||
case 'v':
|
||||
rc = store_option (&cmdline, cmd_keyword_version,
|
||||
optarg);
|
||||
break;
|
||||
case 'g':
|
||||
rc = store_option (&cmdline, cmd_keyword_get_cache,
|
||||
optarg);
|
||||
break;
|
||||
case 'c':
|
||||
rc = check_cache (optarg);
|
||||
if (rc >= 0) {
|
||||
rc = store_option (&cmdline, cmd_keyword_cache,
|
||||
optarg);
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
rc = check_no_cyl (optarg);
|
||||
if (rc >= 0) {
|
||||
rc = store_option (&cmdline,
|
||||
cmd_keyword_no_cyl,
|
||||
optarg);
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
rc = store_option(&cmdline, cmd_keyword_path, optarg);
|
||||
break;
|
||||
case OPT_PATH_RESET_ALL:
|
||||
rc = store_option(&cmdline, cmd_keyword_path_all,
|
||||
optarg);
|
||||
break;
|
||||
case 'S':
|
||||
rc = store_option (&cmdline, cmd_keyword_reserve,
|
||||
optarg);
|
||||
break;
|
||||
case 'L':
|
||||
rc = store_option (&cmdline, cmd_keyword_release,
|
||||
optarg);
|
||||
break;
|
||||
case 'O':
|
||||
rc = store_option (&cmdline, cmd_keyword_slock,
|
||||
optarg);
|
||||
break;
|
||||
case OPT_ENABLE_STATS:
|
||||
rc = store_option(&cmdline, cmd_keyword_enable_stats,
|
||||
optarg);
|
||||
break;
|
||||
case OPT_DISABLE_STATS:
|
||||
rc = store_option(&cmdline, cmd_keyword_disable_stats,
|
||||
optarg);
|
||||
break;
|
||||
case 'P':
|
||||
rc = store_option (&cmdline, cmd_keyword_profile,
|
||||
optarg);
|
||||
break;
|
||||
case 'I':
|
||||
rc = check_prof_item (optarg);
|
||||
if (rc >= 0) {
|
||||
rc = store_option (&cmdline,
|
||||
cmd_keyword_prof_item,
|
||||
optarg);
|
||||
}
|
||||
break;
|
||||
case 'R':
|
||||
rc = store_option (&cmdline, cmd_keyword_reset_prof,
|
||||
optarg);
|
||||
break;
|
||||
case 'Q':
|
||||
rc = store_option (&cmdline, cmd_keyword_query_reserve,
|
||||
optarg);
|
||||
break;
|
||||
|
||||
case -1:
|
||||
/* End of options string - start of devices list */
|
||||
cmdline.device_id = optind;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Try 'tunedasd --help' for more"
|
||||
" information.\n");
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
} while (opt != -1);
|
||||
|
||||
*line = cmdline;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute the command.
|
||||
*/
|
||||
static int do_command(char *device, struct command_line cmdline)
|
||||
{
|
||||
int i, rc;
|
||||
|
||||
rc = 0;
|
||||
for (i = 0; !cmdline.parm[i].kw_given; i++);
|
||||
|
||||
switch (i) {
|
||||
case cmd_keyword_get_cache:
|
||||
rc = disk_get_cache (device);
|
||||
break;
|
||||
case cmd_keyword_cache:
|
||||
rc = disk_set_cache (device,
|
||||
cmdline.parm[cmd_keyword_cache].data,
|
||||
cmdline.parm[cmd_keyword_no_cyl].data);
|
||||
break;
|
||||
case cmd_keyword_no_cyl:
|
||||
break;
|
||||
case cmd_keyword_reserve:
|
||||
rc = disk_reserve (device);
|
||||
break;
|
||||
case cmd_keyword_release:
|
||||
rc = disk_release (device);
|
||||
break;
|
||||
case cmd_keyword_slock:
|
||||
rc = disk_slock (device);
|
||||
break;
|
||||
case cmd_keyword_profile:
|
||||
rc = disk_profile (device,
|
||||
cmdline.parm[cmd_keyword_prof_item].data);
|
||||
break;
|
||||
case cmd_keyword_reset_prof:
|
||||
rc = disk_reset_prof (device);
|
||||
break;
|
||||
case cmd_keyword_prof_item:
|
||||
break;
|
||||
case cmd_keyword_query_reserve:
|
||||
rc = disk_query_reserve_status(device);
|
||||
break;
|
||||
case cmd_keyword_path:
|
||||
rc = disk_reset_chpid(device,
|
||||
cmdline.parm[cmd_keyword_path].data);
|
||||
break;
|
||||
case cmd_keyword_path_all:
|
||||
rc = disk_reset_chpid(device, NULL);
|
||||
break;
|
||||
default:
|
||||
error_print ("Unknown command '%s' specified",
|
||||
get_keyword_name (i));
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable/Disable DASD performance statistics globally by writing
|
||||
* 'set on' or 'set off' to /proc/dasd/statistics.
|
||||
*/
|
||||
static int tunedasd_set_global_stats(int val)
|
||||
{
|
||||
const char *path = "/proc/dasd/statistics";
|
||||
int rc = 0;
|
||||
|
||||
if (val)
|
||||
rc = util_file_write_s("set on", path);
|
||||
else
|
||||
rc = util_file_write_s("set off", path);
|
||||
|
||||
if (rc)
|
||||
error_print("Could not enable/disable performance statistics");
|
||||
else
|
||||
printf("Performance statistics %sabled\n", val ? "en" : "dis");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Main.
|
||||
*/
|
||||
int
|
||||
main (int argc, char* argv[])
|
||||
{
|
||||
struct command_line cmdline;
|
||||
int rc, finalrc;
|
||||
|
||||
/* Find out what we're supposed to do */
|
||||
rc = get_command_line (argc, argv, &cmdline);
|
||||
if (rc) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
rc= check_key_state (&cmdline);
|
||||
if (rc) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check for priority options --help and --version */
|
||||
if (cmdline.parm[cmd_keyword_help].kw_given) {
|
||||
print_usage ();
|
||||
return 0;
|
||||
} else if (cmdline.parm[cmd_keyword_version].kw_given) {
|
||||
util_prg_print_version();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Make sure we're running as root */
|
||||
if (check_for_root ()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Enable/Disable performance statistics */
|
||||
if (cmdline.parm[cmd_keyword_enable_stats].kw_given)
|
||||
return tunedasd_set_global_stats(1);
|
||||
if (cmdline.parm[cmd_keyword_disable_stats].kw_given)
|
||||
return tunedasd_set_global_stats(0);
|
||||
|
||||
/* Do each of the commands on each of the devices
|
||||
* and don't care about the return codes */
|
||||
if (cmdline.device_id >= argc) {
|
||||
error_print ("Missing device");
|
||||
print_usage ();
|
||||
return 1;
|
||||
}
|
||||
|
||||
finalrc = 0;
|
||||
while (cmdline.device_id < argc) {
|
||||
rc = do_command (argv[cmdline.device_id], cmdline);
|
||||
if (rc && !finalrc)
|
||||
finalrc = rc;
|
||||
cmdline.device_id++;
|
||||
}
|
||||
return finalrc;
|
||||
}
|
||||
Reference in New Issue
Block a user