vdmtest(7) DG/UX R4.11MU05 vdmtest(7)
NAME
vdmtest - Virtual Disk Manager Test Subdriver
DESCRIPTION
The Test Subdriver is used to inject faults into virtual disk
hierarchies to test recovery from simulated disk I/O failures. Full
disk failures can be simulated, as well as media failures for
particular disk blocks.
Usually test instances are inserted above a physical instance so that
bad blocks and disk failures can be simulated for the whole physical
disk. However, they can be inserted anywhere in a virtual disk
hierarchy in order to test failures between specific parent and child
virtual disks.
Pictorially, a test instance inserted above a physical instance looks
like this:
+-------------------+
| test instance |
+-------------------+
|
|
|
+-------------------+
| physical |
| sd(ncsc(0,7),0,0) |
+-------------------+
|
|
----------
( )
( )
( disk )
( drive )
( 1 )
( )
----------
A test instance always has one child, the instance it is testing.
Test instances are inserted between a parent and child instance in
order to simulate I/O failures from the child to the parent.
In order to use the Test Subdriver, you must configure vdmtest() into
your kernel. It does not appear by default in new system files since
it is designed for debugging purposes only. You must configure it
into the system file if you wish to use it.
For more details about how the Test Subdriver fits into the Virtual
Disk Manager, see the vdm(7) man page.
SIMULATING I/O FAILURES
Test instances can simulate these types of I/O failures:
· Physical unit failure of the whole test instance. All I/O
requests return an error.
· Bad blocks on read I/Os to the test instance. This simulates
an unmapped (and unmappable) read bad block failure.
· Bad blocks on write I/Os to the test instance. This simulates
an unmapped (but mappable) write bad block failure.
Additionally, full disk failures can be repaired within the test
instance, so transient I/O failure recovery can be tested.
Recovery from individual block failures is not implemented. The
DG_VDMTEST_REPAIR_BLOCKS command cannot be used.
All test I/O failures are removed when the test instance is deleted
or extracted. Remove the test instance to recover from individual
block failures.
See the vdmremap(1M) man page for more details about bad-block I/O
failure recovery.
PERSISTENCE
Test instances are non-persistent, which means they are never stored
in the VDIT on disk. They exist in memory only and will be torn down
when a system is rebooted. Since they are for debugging purposes
only, there is no reason for them to be persistent.
When you create or insert test instance, you must make them non-
persistent.
USABILITY
A test instance is always usable as long as its child is usable.
CLUSTER DISKS
Test instances may be used on cluster disks to simulate I/O failures
to test recovery. All test functionality is supported on cluster
disks.
Note, however, that any I/O failure induced by the test instance on
one cluster node only affects the instances on that node. The other
nodes in the cluster will not notice the I/O failure. This simulates
the way I/O failures from disk controllers behave.
ADMVDISK
The admvdisk(1M) command does not contain any support for test
instances, since they are designed for debugging purposes only. If
you wish to use test instances to inject I/O faults to test recovery
of your applications, you must write custom programs to insert and
manage the test instances according to your needs.
PROGRAMMING INTERFACE
The ioctl(2) system call is used for all communication with the Test
Subdriver. Use the open(2) system call to open a channel to the
/dev/vdm node, and issue all ioctl(2) commands through that channel.
See vdm(7) for more details on the programming interface.
The <sys/ioctl.h> include file is required for communicating with the
Test Subdriver. The <errno.h>, <sys/dg_sysctl.h>, <sys/types.h>,
<stdio.h>, and <unistd.h> include files will be helpful.
SUBDRIVER-SPECIFIC COMMANDS
DG_VDMTEST_REPAIR_BLOCKS
Mark a set of blocks as repaired. This undoes the effects of a
DG_VDMTEST_FAIL_BLOCKS_ON_READ or DG_VDMTEST_FAIL_BLOCKS_ON_WRITE
ioctl(2) command.
DG_VDMTEST_FAIL_INSTANCE
Mark the instance to return error EIO on any I/O request to the
instance.
DG_VDMTEST_REPAIR_INSTANCE
Mark the instance as repaired so I/O can be done normally. This
undoes the effects of a DG_VDMTEST_FAIL_INSTANCE ioctl(2) command.
DG_VDMTEST_FAIL_BLOCKS_ON_READ
Mark a set of blocks as bad. This causes read operations directed to
those blocks to generate an EIO error.
DG_VDMTEST_FAIL_BLOCKS_ON_WRITE
Mark a set of blocks as bad. This causes write operations directed
to those blocks to generate an EIO error.
COMMON DISK COMMANDS
The following commands are common to all device drivers that manage
physical disks. The VDM and the subdrivers support the commands on
virtual disks as well, because they present the same interfaces as
physical disks.
DSKIOCGET
This command returns the size of the virtual disk in sectors. For
virtual disks, one sector is one disk block, or 512 bytes. The
command and associated structure is described in more detail in
dsk(7).
DSKIOCUSAGE
This command returns I/O count and performance statistics on the I/O
issued to a virtual disk. The command and associated packet is
described in more detail in dsk(7).
SUBDRIVER-SPECIFIC DEFINES
DG_VDMTEST_SUBDRIVER_ID
The unique ID that identifies the Test Subdriver.
DG_VDMTEST_IOCTL_PACKET_VERSION_0
The version zero stamp used in all Test Subdriver ioctl(2) packets.
The stamp indicates which version of the Test Subdriver interface is
being used and allows the Test Subdriver to support previous versions
without requiring that applications be recompiled.
STRUCTURES
dg_vdmtest_create_packet
The Test Subdriver ioctl(2) packet for creating a new test instance.
Put a pointer to this packet into the packet for the
DG_VDM_CREATE_INSTANCE command.
struct dg_vdmtest_create_packet
{
int version;
dev_t child_device_number;
};
version
The version of the packet.
child_device_number
The device number of the child instance that this test
instance is to manage.
dg_vdmtest_fail_blocks
The Test Subdriver ioctl(2) packet for specifying what blocks are to
be failed for a test instance. Put a pointer to this packet into the
argument field of the packet for the DG_VDM_IOCTL_SUBDRIVER command,
and set the command field to DG_VDMTEST_FAIL_BLOCKS_ON_READ or
DG_VDMTEST_FAIL_BLOCKS_ON_WRITE. Put the device number of the test
instance to update in the instance device number field.
struct dg_vdmtest_fail_blocks
{
int version;
daddr_t starting_block;
unsigned int number_of_blocks;
};
version
The version of the packet.
starting_block
The starting block number for a span of blocks to be reported
as bad. Block numbers are zero-based.
number_of_blocks
The number of blocks from the starting block to be reported as
bad.
EXAMPLES
The following code fragments illustrate how to use the packets and
commands described in this man page. The fragments are not complete
and are not intended to be compilable or executable. In particular,
initialization code, instance locating code, and error handling are
left out for brevity.
Common includes and variables
#include <errno.h>
#include <sys/dg_sysctl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
int status; /* status from system call */
int vdm_channel; /* channel to /dev/vdm node */
Create a test instance
dev_t test_instance;
dev_t child_instance;
struct dg_vdm_create_instance_packet create_pkt;
struct dg_vdmtest_create_packet test_create_pkt;
create_pkt.version = DG_VDM_IOCTL_PACKET_VERSION_0;
create_pkt.subdriver_id = DG_VDMTEST_SUBDRIVER_ID;
create_pkt.persistent = 0;
create_pkt.enable_disk_updates = 0;
create_pkt.instance_name [0] = '\0';
create_pkt.subdriver_attributes_packet_ptr = &test_create_pkt;
test_create_pkt.version = DG_VDMTEST_IOCTL_PACKET_VERSION_0;
test_create_pkt.child_device_number = child_device;
status = ioctl (vdm_channel,
DG_VDM_CREATE_INSTANCE,
&create_pkt);
test_instance = create_pkt.device_number;
printf ("Test device number = 0x%08x\n", test_instance);
Insert a test instance
dev_t test_instance;
dev_t dummy_instance;
dev_t insert_instance;
dev_t child_instance;
struct dg_vdm_create_instance_packet create_pkt;
struct dg_vdm_insert_instance_packet insert_pkt;
struct dg_vdmtest_create_packet test_create_pkt;
/* Create a non-persistent dummy instance. */
create_pkt.version = DG_VDM_IOCTL_PACKET_VERSION_0;
create_pkt.subdriver_id = DG_VDMDUMMY_SUBDRIVER_ID;
create_pkt.persistent = 0;
create_pkt.enable_disk_updates = 0;
create_pkt.instance_name [0] = '\0';
create_pkt.subdriver_attributes_packet_ptr = NULL;
status = ioctl (vdm_channel,
DG_VDM_CREATE_INSTANCE,
&create_pkt);
dummy_instance = create_pkt.device_number;
/* Insert a test instance. */
insert_pkt.version = DG_VDM_IOCTL_PACKET_VERSION_0;
insert_pkt.instance_to_change = insert_instance;
insert_pkt.dummy_instance = dummy_instance;
insert_pkt.subdriver_id = DG_VDMTEST_SUBDRIVER_ID;
insert_pkt.attributes_packet_ptr = &test_create_pkt;
test_create_pkt.version = DG_VDMTEST_IOCTL_PACKET_VERSION_0;
test_create_pkt.child_device_number = dummy_instance;
status = ioctl (vdm_channel,
DG_VDM_INSERT_INSTANCE,
&insert_pkt);
test_instance = insert_instance;
child_instance = dummy_instance;
Extract a test instance
dev_t test_instance;
dev_t child_instance;
dev_t dummy_instance;
dev_t extract_instance;
struct dg_vdm_create_instance_packet create_pkt;
struct dg_vdm_delete_instance_packet delete_pkt;
struct dg_vdm_extract_instance_packet extract_pkt;
/* Create a non-persistent dummy instance. */
create_pkt.version = DG_VDM_IOCTL_PACKET_VERSION_0;
create_pkt.subdriver_id = DG_VDMDUMMY_SUBDRIVER_ID;
create_pkt.persistent = 0;
create_pkt.enable_disk_updates = 0;
create_pkt.instance_name [0] = '\0';
create_pkt.subdriver_attributes_packet_ptr = NULL;
status = ioctl (vdm_channel,
DG_VDM_CREATE_INSTANCE,
&create_pkt);
dummy_instance = create_pkt.device_number;
/* Extract the test instance. */
extract_pkt.version = DG_VDM_IOCTL_PACKET_VERSION_0;
extract_pkt.parent_device_number = extract_instance;
extract_pkt.new_parent_device_number = dummy_instance;
status = ioctl (vdm_channel,
DG_VDM_EXTRACT_INSTANCE,
&extract_pkt);
test_instance = dummy_instance;
dummy_instance = child_instance;
/* Delete the leftover instance and the child dummy instance. */
delete_pkt.version = DG_VDM_IOCTL_PACKET_VERSION_0;
delete_pkt.device_number = test_instance;
status = ioctl (vdm_channel,
DG_VDM_DELETE_INSTANCE,
&delete_pkt);
delete_pkt.device_number = dummy_instance;
status = ioctl (vdm_channel,
DG_VDM_DELETE_INSTANCE,
&delete_pkt);
Get the children of a test instance
int i;
dev_t test_instance;
dev_t child_instance;
struct dg_vdm_child_instance_packet child_pkt;
struct dg_vdm_get_child_instance_packet get_child_pkt;
get_child_pkt.version = DG_VDM_IOCTL_PACKET_VERSION_0;
get_child_pkt.key = 0;
get_child_pkt.parent_device_number = test_instance;
get_child_pkt.parent_subdriver_id = DG_VDMTEST_SUBDRIVER_ID;
get_child_pkt.available = 0;
get_child_pkt.child_instance_array_ptr = NULL;
status = ioctl (vdm_channel,
DG_VDM_GET_CHILD_INSTANCE,
&get_child_pkt);
printf ("Number of children = %d\n",
get_child_pkt.number_of_children);
get_child_pkt.key = 0;
get_child_pkt.available = 1;
get_child_pkt.child_instance_array_ptr = &child_pkt;
child_pkt.child_role_packet_ptr = NULL;
test_get_child_pkt.version = DG_VDMTEST_IOCTL_PACKET_VERSION_0;
i = 0;
while (1)
{
status = ioctl (vdm_channel,
DG_VDM_GET_CHILD_INSTANCE,
&get_child_pkt);
if ((status == -1) && (errno == ENOENT))
{
break;
}
printf ("Child %d\n", i);
if (child_pkt.child_instance.device_number_used)
{
child_instance = child_instance_pkt.child_instance.
specifier_value.device_number;
printf ("Child device number = 0x%08x\n", child_instance);
if (child_pkt.child_subdriver_id ==
DG_VDM_SUBDRIVER_ID_OF_A_NON_VDM_DEVICE)
{
printf (" Non-vdm child\n");
}
else
{
printf (" Child subdriver 0x%08x\n",
child_pkt.child_subdriver_id);
}
}
else
{
printf (" Missing child ID %08x,%08x\n",
child_pkt.child_instance.specifier_value.id.generation,
child_pkt.child_instance.specifier_value.id.system_id);
}
printf ("\n");
i++;
}
Set a test instance to fail all I/O
dev_t test_instance;
struct dg_vdm_ioctl_subdriver_packet ioctl_pkt;
ioctl_pkt.version = DG_VDM_IOCTL_PACKET_VERSION_0;
ioctl_pkt.subdriver_id = DG_VDMTEST_SUBDRIVER_ID;
ioctl_pkt.instance_device_number = test_instance;
ioctl_pkt.command = DG_VDMTEST_FAIL_INSTANCE;
ioctl_pkt.argument = NULL;
status = ioctl (vdm_channel,
DG_VDM_IOCTL_SUBDRIVER,
&ioctl_pkt);
Repair a test instance from a fail instance command
dev_t test_instance;
struct dg_vdm_ioctl_subdriver_packet ioctl_pkt;
ioctl_pkt.version = DG_VDM_IOCTL_PACKET_VERSION_0;
ioctl_pkt.subdriver_id = DG_VDMTEST_SUBDRIVER_ID;
ioctl_pkt.instance_device_number = test_instance;
ioctl_pkt.command = DG_VDMTEST_REPAIR_INSTANCE;
ioctl_pkt.argument = NULL;
status = ioctl (vdm_channel,
DG_VDM_IOCTL_SUBDRIVER,
&ioctl_pkt);
Set the test instance to fail reads on ten blocks of the disk
dev_t test_instance;
struct dg_vdm_ioctl_subdriver_packet ioctl_pkt;
struct dg_vdmtest_fail_blocks fail_blocks_pkt;
ioctl_pkt.version = DG_VDM_IOCTL_PACKET_VERSION_0;
ioctl_pkt.subdriver_id = DG_VDMTEST_SUBDRIVER_ID;
ioctl_pkt.instance_device_number = test_instance;
ioctl_pkt.command = DG_VDMTEST_FAIL_BLOCKS_ON_READ;
ioctl_pkt.argument = (int) &fail_blocks_pkt;
fail_blocks_pkt.version = DG_VDMTEST_IOCTL_PACKET_VERSION_0;
fail_blocks_pkt.starting_block = 10000;
fail_blocks_pkt.number_of_blocks = 10;
status = ioctl (vdm_channel,
DG_VDM_IOCTL_SUBDRIVER,
&ioctl_pkt);
Set the test instance to fail writes on ten blocks of the disk
dev_t test_instance;
struct dg_vdm_ioctl_subdriver_packet ioctl_pkt;
struct dg_vdmtest_fail_blocks fail_blocks_pkt;
ioctl_pkt.version = DG_VDM_IOCTL_PACKET_VERSION_0;
ioctl_pkt.subdriver_id = DG_VDMTEST_SUBDRIVER_ID;
ioctl_pkt.instance_device_number = test_instance;
ioctl_pkt.command = DG_VDMTEST_FAIL_BLOCKS_ON_WRITE;
ioctl_pkt.argument = (int) &fail_blocks_pkt;
fail_blocks_pkt.version = DG_VDMTEST_IOCTL_PACKET_VERSION_0;
fail_blocks_pkt.starting_block = 10000;
fail_blocks_pkt.number_of_blocks = 10;
status = ioctl (vdm_channel,
DG_VDM_IOCTL_SUBDRIVER,
&ioctl_pkt);
Get the size of a test instance
dev_t ioctl_instance;
struct dg_vdm_ioctl_subdriver_packet ioctl_pkt;
struct dskget dskget_pkt;
ioctl_pkt.version = DG_VDM_IOCTL_PACKET_VERSION_0;
ioctl_pkt.subdriver_id = DG_VDMTEST_SUBDRIVER_ID;
ioctl_pkt.instance_device_number = ioctl_instance;
ioctl_pkt.command = DSKIOCGET;
ioctl_pkt.argument = (int) &dskget_pkt;
status = ioctl (vdm_channel,
DG_VDM_IOCTL_SUBDRIVER,
&ioctl_pkt);
printf ("Total blocks = %u\n",
dskget_pkt.total_sectors *
(dskget_pkt.bytes_per_sector / 512));
FILES
/dev/dsk
Directory for the block special device nodes for virtual
disks. These are the buffered access device nodes.
/dev/rdsk
Directory for the character special device nodes for virtual
disks. These are the unbuffered (or raw) access device nodes.
/dev/vdm
Device node for issuing all ioctl(2) commands.
/usr/include/sys/ioctl.h
ioctl(2) definitions.
ACCESS CONTROL
Access control for the standard VDM framework commands is controlled
by the VDM itself. See the vdm(7) man page for a listing of these
controls.
Access control for the Test Subdriver commands is controlled by the
subdriver itself.
All users may execute these commands: DG_VDM_GET_CHILD_INSTANCE,
DSKIOCGET, DSKIOCUSAGE.
Only users with appropriate privilege may execute these commands:
DG_VDM_CREATE_INSTANCE, DG_VDMTEST_REPAIR_BLOCKS,
DG_VDMTEST_FAIL_INSTANCE, DG_VDMTEST_REPAIR_INSTANCE,
DG_VDMTEST_FAIL_BLOCKS_ON_READ, DG_VDMTEST_FAIL_BLOCKS_ON_WRITE.
On a generic DG/UX system, appropriate privilege is granted by having
an effective UID of 0 (root). See the appropriate_privilege(5) man
page for more information.
On a system with DG/UX information security, appropriate privilege is
granted by having one or more specific capabilities enabled in the
effective capability set of the user. See the cap_defaults(5) man
page for the default capabilities for these commands.
RETURN VALUE
The return value from the ioctl(2) system call used to issue the
command will be one of the following:
0 The command was successful.
-1 An error occurred. errno is set to indicate the error.
DIAGNOSTICS
There are descriptive extended error message strings available for
most of the error codes. They can be retrieved with the
dg_ext_errno(2), extended_strerror(3C), and extended_perror(3C)
routines.
Errno may be set to one of the DG/UX standard error codes. See
/usr/include/sys/errno.h for a listing of those error codes.
Errno may be set to one of the standard error codes provided by the
VDM framework. See vdm(7) for a listing of those error codes.
Errno may also be set to one of the following error codes that are
specific to this subdriver:
ENOSPC There is no more room available in the table to store
simulated bad blocks.
SEE ALSO
ioctl(2), dsk(7), rdsk(7), vdm(7).
Licensed material--property of copyright holder(s)