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)



vdmaggr(7)                       DG/UX R4.11                      vdmaggr(7)


NAME
       vdmaggr - Virtual Disk Manager Aggregation Subdriver

DESCRIPTION
       The Aggregation Subdriver enables you to combine separate virtual
       disks into a single, large virtual disk that can be larger than the
       size of any single physical disk.  The aggregation pieces may be on
       different physical disks or at different places on a single physical
       disk.  You can use aggregations to gather small chunks of free space
       on several disks together to form a single virtual disk that is a
       usable size.

       Aggregations also support software disk striping, where the data
       blocks are stored round-robin fashion among the aggregation pieces to
       provide a more balanced I/O load to the physical disks.  This can
       improve performance.

       Pictorially, an aggregation containing two pieces looks like this:

                             +-------------------+
                             | aggregation "X11" |
                             | is 120000 blocks  |
                             +-------------------+
                                   |       |
                           +-------+       +-------+
                           |                       |
                 +-------------------+   +-------------------+
                 | piece 0           |   | piece 1           |
                 | partition         |   | partition         |
                 | starts at 50000   |   | starts at 1000    |
                 | is 40000 blocks   |   | is 80000 blocks   |
                 +-------------------+   +-------------------+
                           |                       |
                           |                       |
                           |                       |
                 +-------------------+   +-------------------+
                 | physical          |   | physical          |
                 | sd(ncsc(0,7),0,0) |   | sd(ncsc(0,7),1,0) |
                 +-------------------+   +-------------------+
                           |                       |
                           |                       |
                       ----------              ----------
                      (          )            (          )
                      (          )            (          )
                      (   disk   )            (   disk   )
                      (   drive  )            (   drive  )
                      (     1    )            (     2    )
                      (          )            (          )
                       ----------              ----------

       Aggregations refer to their children as pieces.  So in this example,
       the aggregation has two pieces, each of which is a partition living
       on a different disk drive.

       The current revision of DG/UX supports aggregations that have up to
       approximately 120 pieces.  The actual number possible for any given
       aggregation depends on the amount of free space available in the
       VDITs (Virtual Disk Information Tables) on the physical disks that
       the aggregation spans.  In general, enough free space exists to build
       several maximum sized aggregations.

       In order to use the Aggregation Subdriver, you must configure
       vdmaggr() into your kernel.  It appears in all new system files by
       default, so it is usually already configured.

       For more details about how the Aggregation Subdriver fits into the
       Virtual Disk Manager, see the vdm(7) man page.

   SOFTWARE DISK STRIPING
       In the example above, the aggregation is not striped.  The first N
       blocks of the aggregation will be written to blocks zero through (N -
       1) of piece zero, where N is the size of piece zero.  The next M
       blocks will be written to blocks zero through (M - 1) of piece one,
       where M is the size of piece one.

       This unstriped aggregation is the default organization when you
       create an aggregation.  It is good for general purpose data storage,
       as well as for applications that read or write large sequential I/Os,
       especially if there is only one thread or process doing the I/O.

       Here is what the data blocks for an unstriped aggregation look like:

                             0              119999
                             +-------------------+
                             | aggregation "X11" |
                             | is 120000 blocks  |
                             +-------------------+
                                   |       |
                           +-------+       +-------+
                 0         |     39999   40000     |    119999
                 +-------------------+   +-------------------+
                 | 0, 1, 2, 3, 4, 5, |   | 40000, 40001,     |
                 | 6, 7, 8, 9, 10,   |   | 40002, 40003,     |
                 | 11, 12, 13, 14, ..|   | 40004, 40005, ..  |
                 |                   |   |                   |
                 | piece 0           |   | piece 1           |
                 | partition         |   | partition         |
                 | is 40000 blocks   |   | is 80000 blocks   |
                 +-------------------+   +-------------------+
                           |                       |
                           |                       |
                           |                       |
                       ----------              ----------
                      (          )            (          )
                      (          )            (          )
                      (   disk   )            (   disk   )
                      (   drive  )            (   drive  )
                      (     1    )            (     2    )
                      (          )            (          )
                       ----------              ----------

       A striped aggregation, on the other hand, organizes the data blocks
       within the aggregation in a round-robin fashion.  The splitting of
       I/O requests is done on stripe size boundaries.  The stripe size is
       settable when you create the aggregation.

       Striping is most useful when your application does small, fixed sized
       random reads and writes, especially if multiple threads or processes
       are doing I/O to the same virtual disk at the same time.  By placing
       the data blocks in a round-robin fashion, the likelihood that a
       second I/O request will need to access a different disk to get the
       data blocks increases.

       This means that different I/O requests can be processed in parallel
       more often, and that increases performance.  One request would be
       reading or writing to the first disk, while a second request would
       likely be accessing the second disk.  Since the disks are physically
       separate, they can truly process the two I/O requests in parallel.
       The parallelism increases as you stripe the aggregation across more
       physical disks.

       The same two I/O requests would have to be processed serially if the
       aggregation was not striped and the requests both fell onto the same
       piece of the aggregation.  This is because they would both be
       directed to the same physical disk, which can process only one
       request at a time.  This would limit the performance of the
       application.

       Here is what the data blocks for a striped aggregation look like
       using a stripe size of four blocks:

                             0              119999
                             +-------------------+
                             | aggregation "X11" |
                             | is 120000 blocks  |
                             +-------------------+
                                   |       |
                           +-------+       +-------+
                           |                       |
                 +-------------------+   +-------------------+
                 | 0, 1, 2, 3,       |   | 4, 5, 6, 7,       |
                 | 8, 9, 10, 11,     |   | 12, 13, 14, 15,   |
                 | 16, 17, 18, 19 .. |   | 20, 21, 22, 23 .. |
                 |                   |   |                   |
                 | piece 0           |   | piece 1           |
                 | partition         |   | partition         |
                 | is 60000 blocks   |   | is 60000 blocks   |
                 +-------------------+   +-------------------+
                           |                       |
                           |                       |
                           |                       |
                       ----------              ----------
                      (          )            (          )
                      (          )            (          )
                      (   disk   )            (   disk   )
                      (   drive  )            (   drive  )
                      (     1    )            (     2    )
                      (          )            (          )
                       ----------              ----------

       Notice that the sizes of the partitions had to change in order to use
       software disk striping.  There are additional rules for building
       striped aggregations that are required to make the striping work
       properly.  They are:

       1.     All of the pieces of a striped aggregation must be the same
              size.

       2.     The stripe size must divide evenly into the size of a piece
              (i.e., no remainder).

       3.     The stripe size must be less than or equal to the piece size.

       4.     Striped aggregations cannot be expanded or shrunk, since
              adding or removing pieces would remove chunks of data from all
              parts of the aggregation.

       Choose the stripe size to match the average size of the I/Os that the
       application reads and writes.  Choosing a stripe size smaller than
       the I/O size will mean that all I/Os will have to be broken up and
       issued in multiple requests to read or write the data.  This will
       severely reduce performance.  Choosing a stripe size that is a larger
       multiple of the I/O size may also work well for some applications.

       Good stripe sizes are powers of two, like 16, 32, 64, 128, and 256.
       This is because most disk drives tend to transfer data well at block
       sizes that are powers of two, and applications tend to choose powers
       of two for their I/O sizes.  However, no limits are placed on the
       stripe size, so you may set it to any value that best matches your
       application's needs.

       To ensure that software striping is working efficiently with the
       physical disks, align the start of each piece of the aggregation on a
       stripe block boundary on the physical disk.  Further, each piece of a
       striped aggregation should reside on a different physical disk.

       If you build a DG/UX file system on a striped aggregation, you should
       set the data element size of the file system to the stripe size.
       Alternately, you can set the stripe size to be a larger multiple of
       the data element size.  This will help ensure that the file system
       issues stripe-aligned I/O requests to the virtual disk.  You may want
       to set other file system parameters according to your application's
       needs.

       Generally, you should not use software disk striping and CLARiiON®
       hardware disk striping together, since the two mechanisms will both
       be striping the data and will be working at cross purposes.

       It is hard to predict when software disk striping will benefit
       performance.  If used incorrectly, it can have a negative impact on
       performance as well.  To determine if it will help your applications,
       run performance tests of it on both a non-striped and striped
       aggregation, and choose the data organization that best meets your
       needs.

   USABILITY
       For you to be able to use an aggregation (i.e., open it), all of its
       pieces must be available and usable.  If any pieces are missing, the
       aggregation cannot be opened, and the data in it is unavailable.

       This means that using aggregations reduces the availability of the
       data.  For example, if an aggregation is spread over four disks, a
       failure of any one of the disks means that the whole aggregation is
       unavailable.  This risk is greater than if all of the data were
       stored in a single partition on a single disk drive.

   EXPANDING AND SHRINKING AGGREGATIONS
       Aggregations can be expanded on-line while they are open and the
       virtual disk is in use.  The application using the aggregation must
       be prepared for such an expansion.  The DG/UX file system is, so you
       can expand DG/UX file systems on-line, without unmounting them.  The
       users can continue to read and write to the file system while it is
       being expanded.  However, most database software is not prepared to
       have its regions expanded.  Instead, simply add another region to the
       database.

       Aggregations can likewise be shrunk, but only when the virtual disk
       is closed and not in use.  Applications like the DG/UX file system
       can be made to handle on-line expansions relatively easily, but on-
       line shrinking would be more difficult to build, so the VDM does not
       permit it.  A shrink requires that the data in the portion to be
       removed be migrated out and rewritten to other places in the virtual
       disk.

       There are several ways an aggregation can be expanded or shrunk.
       They are:

       1.     Link a new child piece to the end of the aggregation.  This
              adds additional space to the end of the aggregation.

       2.     If the last piece of the aggregation is a simple partition,
              the partition itself can be expanded.  This also adds space to
              the end of the aggregation.

              In this case, the application doing the expansion must issue a
              DSKIOCGET ioctl(2) command to the aggregation after the
              partition is expanded to inform the aggregation that a child
              piece has changed size.

       3.     Unlink an old child piece from the end of the aggregation.
              This removes space from the end of the aggregation.

       4.     If the last piece of the aggregation is a simple partition,
              the partition itself can be shrunk.  This also removes space
              from the end of the aggregation.

              In this case, the application doing the shrink must issue a
              DSKIOCGET ioctl(2) command to the aggregation after the
              partition is shrunk to inform the aggregation that a child
              piece has changed size.

       5.     If you have a single partition that you wish to expand, but
              there is no contiguous free space following it, insert an
              aggregation on top of it, then link additional pieces to the
              aggregation to expand it.

       In order to successfully expand or shrink a virtual disk, the
       application that owns the data must be involved in the size change
       and probably should initiate it to guarantee that it has placed the
       data in the proper state before, during, and after the size change.
       The DG/UX file system is such an application, and the tools that
       manage them can initiate both file system expansions and shrinks.

       The Aggregation Subdriver also permits pieces to be added or removed
       in the middle of an aggregation, but only when the aggregation is
       closed.  Doing so, however, renders the data in the aggregation
       useless, since the new or removed piece changes the block numbers of
       the blocks in the later pieces.  The sysadm(1M) menus and the
       admvdisk(1M) commands only permit you to add or remove pieces at the
       end of an aggregation for this reason.

   CLUSTER DISKS
       Aggregations may be created on cluster disks and may be striped if
       desired.  The pieces for an aggregation must either all be on cluster
       disks or all be on non-cluster disks.  An aggregation may not span
       both cluster and non-cluster disks.

       However, the current revision of DG/UX does not permit aggregations
       to be expanded or shrunk in any fashion while the disks they reside
       on are clustered.

       To change the size of a cluster aggregation, first close it on all
       but one node (i.e., unmount if it is a file system, shut it down if
       it is a database).  Then deregister the disks on all but one node.
       Be sure to deregister all the disks that the aggregation spans.  On
       the remaining node, uncluster the affected disks, then expand or
       shrink the aggregation as desired.  Finally, cluster the disks again,
       then register them on the other cluster nodes.

   BOOTING FROM AGGREGATIONS
       You can boot from aggregations as long as all of the pieces to the
       virtual disk live on the same physical disk.  This is a bootstrap
       limitation because it can only accept one disk specification on the
       boot command line.

       This means that root can be an aggregation, but must have all of its
       pieces on one physical disk.  The same is true of usr (so that you
       can boot standalone sysadm).

PROGRAMMING INTERFACE
       The ioctl(2) system call is used for all communication with the
       Aggregation 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
       Aggregation Subdriver.  The <errno.h>, <sys/dg_sysctl.h>,
       <sys/types.h>, <stdio.h>, and <unistd.h> include files will be
       helpful.

SUBDRIVER-SPECIFIC COMMANDS
       The Aggregation Subdriver has no subdriver-specific commands.

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).

       This command is also used to trigger parent instances to get the
       sizes of their children again after one of the children has changed
       size.  After you change the size of the child, you must issue
       DSKIOCGET commands to all the ancestors of the child, so that they
       will update their sizes as well.

   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_VDMAGGR_SUBDRIVER_ID
       The unique ID that identifies the Aggregation Subdriver.

   DG_VDMAGGR_IOCTL_PACKET_VERSION_0
       The version zero stamp used in all Aggregation Subdriver ioctl(2)
       packets.

       The stamp indicates which version of the Aggregation Subdriver
       interface is being used and allows the Aggregation Subdriver to
       support previous versions without requiring that applications be
       recompiled.

STRUCTURES
   dg_vdmaggr_create_packet
       The Aggregation Subdriver ioctl(2) packet for creating a new
       aggregation instance.  Put a pointer to this packet into the packet
       for the DG_VDM_CREATE_INSTANCE command.

       struct      dg_vdmaggr_create_packet
           {
           int                 version;
           unsigned int        stripe_size;
           unsigned short      number_of_pieces;
           dev_t *             piece_array_ptr;
           };

       version
              The version of the packet.

       stripe_size
              The number of disk blocks in a stripe, if the aggregation is
              to be striped, or zero if it is not to be striped.  If the
              aggregation is to be striped, all the pieces must be the same
              size, the stripe size must evenly divide into the size of a
              piece, and the stripe size must be less than or equal to the
              size of a piece.

       number_of_pieces
              The number of pieces in the aggregation.

       piece_array_ptr
              A pointer to an array of dev_t variables identifying the
              instances that are the pieces of the aggregation.  Put the
              number of entries in the array in number_of_pieces.

   dg_vdmaggr_get_packet
       The Aggregation Subdriver ioctl(2) packet for getting the attributes
       of an aggregation instance.  Put a pointer to this packet into the
       packet for the DG_VDM_GET_ATTRIBUTES command.

       struct      dg_vdmaggr_get_packet
           {
           int             version;
           unsigned int    stripe_size;
           };

       version
              The version of the packet.

       stripe_size
              The returned stripe size of the aggregation if it is striped,
              or zero if it is not striped.

   dg_vdmaggr_update_packet
       The Aggregation Subdriver ioctl(2) packet for updating the attributes
       of an aggregation instance.  Put a pointer to this packet into the
       packet for the DG_VDM_UPDATE_ATTRIBUTES command.

       Modifying the stripe size of an aggregation will destroy all the data
       in the aggregation.

       struct      dg_vdmaggr_update_packet
           {
           int             version;
           unsigned int    stripe_size;
           };

       version
              The version of the packet.

       stripe_size
              The new number of disk blocks in a stripe, if the aggregation
              is to be striped, or zero if it is not to be striped.  If the
              aggregation is to be striped, all the pieces must be the same
              size, the stripe size must evenly divide into the size of a
              piece, and the stripe size must be less than or equal to the
              size of a piece.

   dg_vdmaggr_get_child_packet
       The Aggregation Subdriver ioctl(2) packet for getting child role
       information about a piece of an aggregation instance.  Put a pointer
       to this packet into the child instance sub-packet for the
       DG_VDM_GET_CHILD_INSTANCE command.

       struct      dg_vdmaggr_get_child_packet
           {
           int             version;
           unsigned int    piece_number;
           };

       version
              The version of the packet.

       piece_number
              The returned piece number of the child.  Piece numbers are
              zero-based.

   dg_vdmaggr_link_child_packet
       The Aggregation Subdriver ioctl(2) packet for linking a new piece
       into an aggregation instance.  Put a pointer to this packet into the
       packet for the DG_VDM_LINK_CHILD_INSTANCE command.

       Linking a new piece into a striped aggregation will destroy all the
       data in the aggregation.

       struct      dg_vdmaggr_link_child_packet
           {
           int             version;
           unsigned int    piece_number;
           };

       version
              The version of the packet.

       piece_number
              The piece number for the new piece.  Piece numbers are zero-
              based.  If the aggregation is open, the piece can be added
              only at the end of the aggregation.

EXAMPLES
       The following code fragments illustrate the use of 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 an aggregation

       dev_t   aggr_instance;
       dev_t   piece_0_instance;
       dev_t   piece_1_instance;
       dev_t   pieces [2];
       struct  dg_vdm_create_instance_packet   create_pkt;
       struct  dg_vdmaggr_create_packet        aggr_create_pkt;

       create_pkt.version             = DG_VDM_IOCTL_PACKET_VERSION_0;
       create_pkt.subdriver_id        = DG_VDMAGGR_SUBDRIVER_ID;
       create_pkt.persistent          = 1;
       create_pkt.enable_disk_updates = 1;
       strcpy (create_pkt.instance_name, "inventory_db");
       create_pkt.subdriver_attributes_packet_ptr = &aggr_create_pkt;

       aggr_create_pkt.version          = DG_VDMAGGR_IOCTL_PACKET_VERSION_0;
       aggr_create_pkt.stripe_size      = 0;
       aggr_create_pkt.number_of_pieces = 2;
       aggr_create_pkt.piece_array_ptr  = pieces;

       pieces [0] = piece_0_instance;
       pieces [1] = piece_1_instance;

       status = ioctl (vdm_channel,
                       DG_VDM_CREATE_INSTANCE,
                       &create_pkt);

       aggr_instance = create_pkt.device_number;

       printf ("Aggregation device number = 0x%08x\n", aggr_instance);

   Update an aggregation's stripe size

       dev_t   update_instance;
       struct  dg_vdm_update_attributes_packet     update_attrs_pkt;
       struct  dg_vdmaggr_update_packet            aggr_update_pkt;

       update_attrs_pkt.version                = DG_VDM_IOCTL_PACKET_VERSION_0;
       update_attrs_pkt.instance_device_number = update_instance;
       update_attrs_pkt.subdriver_id           = DG_VDMAGGR_SUBDRIVER_ID;
       update_attrs_pkt.subdriver_attributes_packet_ptr = &aggr_update_pkt;

       aggr_update_pkt.version     = DG_VDMAGGR_IOCTL_PACKET_VERSION_0;
       aggr_update_pkt.stripe_size = 32;

       status = ioctl (vdm_channel,
                       DG_VDM_UPDATE_ATTRIBUTES,
                       &update_attrs_pkt);

   Get an aggregation's attributes

       dev_t   get_instance;
       struct  dg_vdm_get_attributes_packet    get_attrs_pkt;
       struct  dg_vdmaggr_get_packet           aggr_get_pkt;

       get_attrs_pkt.version                = DG_VDM_IOCTL_PACKET_VERSION_0;
       get_attrs_pkt.instance_device_number = get_instance;
       get_attrs_pkt.subdriver_id           = DG_VDMAGGR_SUBDRIVER_ID;
       get_attrs_pkt.subdriver_attributes_packet_ptr = &aggr_get_pkt;

       aggr_get_pkt.version = DG_VDMAGGR_IOCTL_PACKET_VERSION_0;

       status = ioctl (vdm_channel,
                       DG_VDM_GET_ATTRIBUTES,
                       &get_attrs_pkt);

       printf ("Stripe size = %u\n", aggr_get_pkt.stripe_size);

   Insert an aggregation

       dev_t   aggr_instance;
       dev_t   dummy_instance;
       dev_t   insert_instance;
       dev_t   piece_instance;
       dev_t   pieces [1];
       struct  dg_vdm_create_instance_packet   create_pkt;
       struct  dg_vdm_insert_instance_packet   insert_pkt;
       struct  dg_vdmaggr_create_packet        aggr_create_pkt;

       /*  Create a dummy instance. */

       create_pkt.version             = DG_VDM_IOCTL_PACKET_VERSION_0;
       create_pkt.subdriver_id        = DG_VDMDUMMY_SUBDRIVER_ID;
       create_pkt.persistent          = 1;
       create_pkt.enable_disk_updates = 1;
       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 an aggregation. */

       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_VDMAGGR_SUBDRIVER_ID;
       insert_pkt.attributes_packet_ptr = &aggr_create_pkt;

       aggr_create_pkt.version          = DG_VDMAGGR_IOCTL_PACKET_VERSION_0;
       aggr_create_pkt.stripe_size      = 0;
       aggr_create_pkt.number_of_pieces = 1;
       aggr_create_pkt.piece_array_ptr  = pieces;

       pieces [0] = dummy_instance;

       status = ioctl (vdm_channel,
                       DG_VDM_INSERT_INSTANCE,
                       &insert_pkt);

       aggr_instance  = insert_instance;
       piece_instance = dummy_instance;

   Extract an aggregation

       dev_t   aggr_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 dummy instance. */

       create_pkt.version             = DG_VDM_IOCTL_PACKET_VERSION_0;
       create_pkt.subdriver_id        = DG_VDMDUMMY_SUBDRIVER_ID;
       create_pkt.persistent          = 1;
       create_pkt.enable_disk_updates = 1;
       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 aggregation. */

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

       aggr_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 = aggr_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);

   Link a piece to an aggregation

       dev_t   link_instance;
       dev_t   new_piece_instance;
       struct  dg_vdm_link_child_instance_packet   link_pkt;
       struct  dg_vdmaggr_link_child_packet        aggr_link_pkt;

       link_pkt.version               = DG_VDM_IOCTL_PACKET_VERSION_0;
       link_pkt.parent_device_number  = link_instance;
       link_pkt.parent_subdriver_id   = DG_VDMAGGR_SUBDRIVER_ID;
       link_pkt.child_device_number   = new_piece_instance;
       link_pkt.child_packet_ptr      = &aggr_link_pkt;

       aggr_link_pkt.version      = DG_VDMAGGR_IOCTL_PACKET_VERSION_0;
       aggr_link_pkt.piece_number = 2;

       status = ioctl (vdm_channel,
                       DG_VDM_LINK_CHILD_INSTANCE,
                       &link_pkt);

   Get the children of an aggregation

       dev_t   aggr_instance;
       dev_t   child_instance;

       struct  dg_vdm_child_instance_packet        child_pkt;
       struct  dg_vdm_get_child_instance_packet    get_child_pkt;
       struct  dg_vdmaggr_get_child_packet         aggr_get_child_pkt;

       get_child_pkt.version                  = DG_VDM_IOCTL_PACKET_VERSION_0;
       get_child_pkt.key                      = 0;
       get_child_pkt.parent_device_number     = aggr_instance;
       get_child_pkt.parent_subdriver_id      = DG_VDMAGGR_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 = &aggr_get_child_pkt;

       aggr_get_child_pkt.version = DG_VDMAGGR_IOCTL_PACKET_VERSION_0;

       while (1)
           {
           status = ioctl (vdm_channel,
                           DG_VDM_GET_CHILD_INSTANCE,
                           &get_child_pkt);

           if ((status == -1) && (errno == ENOENT))
               {
               break;
               }

           printf ("Piece %u\n", aggr_get_child_pkt.piece_number);

           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");
           }

   Unlink a piece from an aggregation

       dev_t   unlink_instance;
       dev_t   child_instance;
       struct  dg_vdm_unlink_child_instance_packet   unlink_pkt;

       unlink_pkt.version               = DG_VDM_IOCTL_PACKET_VERSION_0;
       unlink_pkt.parent_device_number  = unlink_instance;
       unlink_pkt.child_instance.device_number_used = 1;
       unlink_pkt.child_instance.specifier_value.device_number =
           child_instance;

       status = ioctl (vdm_channel,
                       DG_VDM_UNLINK_CHILD_INSTANCE,
                       &unlink_pkt);

   Get the size of an aggregation

       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_VDMAGGR_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 Aggregation Subdriver commands is controlled
       by the subdriver itself.  Below is the listing of these commands.

       All users may execute these commands: DSKIOCGET (to get the size of
       an instance), and DSKIOCUSAGE.

       Only users with appropriate privilege may execute these commands:
       DSKIOCGET (to change the size of a parent instance).

       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:

       EBUSY  The piece number is not valid while the aggregation is open.

       EBUSY  Cannot update an aggregation's attributes while it is open.

       EBUSY  Cannot resize a striped aggregation while it is open.

       EBUSY  Cannot resize any piece of an open aggregation except for the
              last one.

       EINVAL There are no aggregation pieces specified.

       EINVAL The aggregation piece number is not valid.

       EINVAL Cannot remove the last piece from an aggregation.

       EINVAL All pieces in a striped aggregation must be the same size.

       EINVAL The aggregation stripe size must evenly divide into the piece
              size.

       EINVAL The aggregation stripe size must be less than or equal to the
              piece size.

       ENXIO  The virtual disk is not a piece of the aggregation.

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