Museum

Home

Lab Overview

Retrotechnology Articles

⇒ Online Manual

Media Vault

Software Library

Restoration Projects

Artifacts Sought

Related Articles

ioctl(2)

dsk(7)

rdsk(7)

vdm(7)



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)

Typewritten Software • bear@typewritten.org • Edmonds, WA 98026