Museum

Home

Lab Overview

Retrotechnology Articles

Online Manuals

⇒ vdm(7) — DG/UX 5.4R3.00

Media Vault

Software Library

Restoration Projects

Artifacts Sought

Related Articles

vdmphys(7)

vdmpart(7)

vdmaggr(7)

vdmmirr(7)

vdmremap(7)

vdmmpio(7)

ioctl(2)

iso-88591(5)



vdm(7)                         DG/UX 5.4R3.00                         vdm(7)


NAME
       vdm - Virtual Disk Manager interface

SYNOPSIS
       #include <limits.h>
       #include <sys/ioctl.h>
       #include <sys/types.h>

       ioctl(int fildes, int command, int argument);

DESCRIPTION
       The Virtual Disk Manager is a device driver. Since it does not
       provide access to a specific physical device, it is referred to as a
       pseudo-device driver and the devices it manages are referred to as
       pseudo-devices.

       VDM is a framework that facilitates the implementation and use of
       high level disk functions like disk mirroring and disk partitioning.
       Each function implemented is also a pseudo-device driver that runs
       under the VDM framework to simplify its implementation and use.  For
       this reason, they are called subdrivers.  The following are some of
       the subdrivers implemented to work under the VDM. This list may grow
       as new subdrivers are implemented:

       Mirror         Duplicates writes for redundancy to provide more
                      reliable disks

       Cache          Utilizes a faster disk to improve the speed of a
                      slower disk

       Aggregation    Concatenates disks together to build larger disks

       Partition      Divides disks to facilitate the sharing of a disk

       Physical       Communicates with the physical device drivers

       Although the functionalities provided by subdrivers emulate and/or
       enhance the capability of disks, in general, they interface directly
       with physical device drivers.  The Physical Subdriver was implemented
       for this purpose.  All other subdrivers interface with each other
       through a standard set of interfaces.  In this way, for example,
       mirrors can be partitioned as well as mirroring partitions.

       The ability to build any combination of subdrivers into a complex set
       of functions is extremely powerful, but the VDM provides two
       additional services to the subdrivers:

       1.     The combination of subdrivers used to implement a set of
              functions can be changed at any time, even while the functions
              are in use.

       2.     The combination of subdrivers can be remembered through system
              reboots, even when the disk drives are moved to another
              machine.



Licensed material--property of copyright holder(s)                         1




vdm(7)                         DG/UX 5.4R3.00                         vdm(7)


       The first service provides high availability through on-line
       manipulations.  This allows administrators to perform the following
       functions while the system and data is in use: configure new devices,
       backup file systems, improve file system reliability, improve file
       system performance. The second service offers the ability to save
       manipulations from one system reboot to another as well as
       facilitating the use of data created on one system to be used on
       another system.

   Subdrivers
       As mentioned previously, a subdriver is a device driver that
       represents the implementation of a specific disk function.  It is
       written specifically to work under VDM.  Typically the implementation
       of a subdriver is much simpler than the same function written without
       VDM because it can make use of many utility functions available
       within the VDM.

   Instances
       To apply a subdriver's function, an abstract entity, called an
       instance, must be created.  First, instances of the Physical
       Subdriver are created on top of the physical disks on the system.
       The physical instance is referred to as the parent and the physical
       disk is referred to as the child.  With the exception of some special
       instances, most instances of a subdriver will have children.  The
       role each child plays in its parent instance is defined by the parent
       instance's subdriver.  Some examples of these relationships are
       described below.

       The next step might be the creation of instances of the Partition
       Subdriver where each instance represents a portion of the physical
       instance.  In this case, each partition is a parent and the physical
       instance is the child.  It is common for a physical instance to have
       many parents.

       Next, partitions can be aggregated together to build an instance that
       appears to be contiguous disk space even though it is possibly spread
       over many disk drives.  An aggregation instance may have many
       children.

       Finally, a mirror can be created on top of two aggregation instances,
       partition instances, or any combination of instance types.

   Attributes
       Every subdriver creates and maintains information that is stored with
       an instance it manages.  For example, the instances that are managed
       by the Partition Subdriver have an attributes area describing the
       size and start of the partition.  The framework of the VDM only
       manages the pointer to the attributes area and is oblivious to its
       contents.  The subdriver is the sole manager of the attributes data.

       Many of the commands listed below contain fields that point to
       structures defined by the subdrivers.  They are all declared void *
       to allow them to point to anything. The content of each of these
       structures along with their purpose will be described in each



Licensed material--property of copyright holder(s)                         2




vdm(7)                         DG/UX 5.4R3.00                         vdm(7)


       subdriver's man page.  Included here are the command descriptions for
       the VDM commands.

USER INTERFACE
       To communicate with the VDM device driver, the ioctl(2) system call
       is used.  The fildes argument is the file descriptor returned from
       open(2)ing the device node /dev/vdm.  This device node will exist
       only if the vdm() device is configured into the kernel. The command
       and argument parameters to the ioctl(2) call are defined below.

       Many of the commands require a subdriver to be identified by its
       subdriver ID defined in each subdriver's man page.

   Instance Identification
       Many of the commands described below either accept or return instance
       names.  Unless otherwise noted, all of the name arguments are
       character arrays of length DGVDMMAXINSTANCENAMELENGTH including
       a required NUL termination.  Therefore, the number of characters
       allowed in an instance name is one less than the above length.

       Instance names can contain any ISO 8859-1 characters (see
       iso-88591(5)) except the following:

       space    A space character.

       "        A double quote character.

       '        A single quote character.

       (        A left parenthesis.

       )        A right parenthesis.

       ,        A comma character.

       /        A slash character.

       :        A colon character.

       @        A commercial at character.

       An instance name can also be of zero length (one NUL terminator) if a
       name is not required. Additionally, instance names are not required
       to be unique.  Although this provides flexibility, it also makes it
       more difficult to identify instances for the purpose of manipulation.
       For this reason, instances can be identified using an instance ID.
       The instance ID is a 64 bit value where 32 bits contain a system
       identifier (CPU stamp) and 32 bits contain a generation number unique
       to each instance on a machine.  These two numbers guarantee that
       there will never be another instance with the same instance ID unless
       the instance is duplicated on a physical disk (the physical disk is
       copied or duplicated with hardware mirroring).

       Because an instance ID can be cumbersome to use, it can be translated



Licensed material--property of copyright holder(s)                         3




vdm(7)                         DG/UX 5.4R3.00                         vdm(7)


       into a device number.  A device number is only guaranteed to be
       unique for an instance until a system is rebooted.  For this reason,
       it is inappropriate to store device numbers on disk (in files).  An
       instance name or instance ID can be used to obtain an instance's
       current device number using dgsysctl(2).  This system call supports
       two name translation interfaces: DGSYSCTLNAMETODEVICE and
       DGSYSCTLDEVICETONAME. For instance names, the arg parameter of
       the dgsysctl(2) command is a pointer to a character string of the
       form:

           vdm(instance-name,generation-number,system-id,number)

       The instance-name argument has already been described.  The
       generation-number is a unique number to a specific system.  However,
       if the instance is taken to another system, then there is no
       guarantee that this alone would uniquely identify an instance.
       Therefore, the system-id is used to establish a universal identifier.
       The combination of the system-id and the generation-number is the
       instance ID.  If a physical disk is copied, the instance ID is not
       enough to uniquely identify an instance if both copies of the
       instance are introduced into the system.  Therefore, the number is
       the last argument and it is used to uniquely identify duplicate
       copies of instances.

       All of the above arguments are optional and any combination of
       arguments can be supplied.  For example, you can supply the instance-
       name with the system-id.  The commas are still necessary to maintain
       argument correspondence.  An example of a device name of the above
       description is:

           vdm(foo,,ff834a3b).

       The dgsysctl(2) call will return 0 if the given device name uniquely
       identifies an instance.  The call will return -1 and errno will be
       set to ENOTUNIQ if the given device name does not uniquely identify
       the instance.  The call will return -1 and errno will be set to ENXIO
       if no instance exists which matches the given identification
       parameters.  The errno will also be set to ENXIO if the VDM device
       driver (vdm()) has not been configured into the system.

       If an instance is identical to another instance (same name, ID...) as
       a result of a physical disk being copied or mirrored, the duplicate
       number (described above) is assigned as the duplicates are seen.
       Therefore, a duplicate's device name is dependent on the order that
       the devices are seen by the system.

       If none of these arguments is supplied (i.e. vdm()), the device
       number returned is used to identify those operations not intended to
       manipulate a specific device, but to talk to the VDM device driver.
       This special device number is the number used to create the /dev/vdm
       device node.

   Instance Specification
       Some instances may have once existed on a system but are no longer



Licensed material--property of copyright holder(s)                         4




vdm(7)                         DG/UX 5.4R3.00                         vdm(7)


       available because the disk on which they resided failed or was
       removed from the system.  Some instances on the system may still
       reference these missing instances as children.  For this reason, the
       children need to be identified when an instance's children are listed
       and unlinked (removed) from an instance.

       For this reason, some of the commands listed below use an instance
       specifier.  For instances that still exist on the system, its device
       number will adequately identify it.  For missing instances, the
       instance ID will need to be used.

       Here is the structure used in some of the commands:

       struct dgvdminstancespecifier
           {
           unsigned short  devicenumberused;
           union
            {
               unsigned int    id[DGVDMINSTANCEIDWORDS];
               devt           devicenumber;
            } specifiervalue;
           };

       If the devicenumberused field is set to 1, the devicenumber
       specifiervalue is used in the union; otherwise, the id field is
       used.

   Versioning
       All of the command structures described below contain version fields.
       These fields are used to provide forward compatibility for programs
       using the ioctl(2) interface described here.  For now, these fields
       should only be set to DGVDMIOCTLPACKETVERSION0.  If the
       interface to a packet changes, this document would describe the
       appropriate value that should be assigned to the version field to
       make use of the new packet format.  Also, every byte in the packet
       should be filled with zero before the individual fields are set.

   Open Instances
       In this document, instances are referred to as in use or open.  An
       instance is in this state when it is either open(2)ed, swapon(2)ed,
       or mount(2)ed.  An instance is also open if it is the child of
       another instance.  In this case, the child instance is opened by its
       parent.

   Error Handling
       When one ioctl(2) commands described below fails.  The call will
       return a -1 and errno will be set to an appropriate value indicating
       the cause of the error.  Additionally, the dgexterrno() can be used
       to provide more information.

       There are a set of common error conditions that can be returned from
       various commands.  These are described here:

       ENOENT        Whenever a listing command is used, errno is set to



Licensed material--property of copyright holder(s)                         5




vdm(7)                         DG/UX 5.4R3.00                         vdm(7)


                     this when there are no more entries to be listed.  If a
                     key field is being used to control the listing, a bad
                     value for this field (any value other than the initial
                     setting of 0) may result being set to this.

       ENXIO         If the command for which this error is returned is
                     attempting to identify an instance (a device number has
                     been supplied), this indicates the the instance could
                     not be found.  This error is also returned if a
                     subdriver is being identified but it is not configured
                     into the system.  When performing I/O, this error is
                     returned if the start of the request is greater than or
                     equal to the size of the instance.

       EINVAL        One of the values in the given command packet is
                     invalid.

       EOPNOTSUP     The version number of a given command packet is not
                     supported.  This can also be returned if the current
                     release does not support the given command.

       EBUSY         An operation is not compatible with the current usage
                     of one of the instances involved in the operation.
                     Typically, the instance is open and the operation
                     requires it to be closed.

       ENOMEM        The system was not able to allocate sufficient memory
                     to perform the requested operation.  This may be the
                     result of insufficient resources or a field value in
                     the operation packet that is mistakenly larger than
                     necessary.


IOCTLS
       The ioctls supported by the VDM are listed below:

   DGVDMCREATEINSTANCE
       This command creates an instance. The argument is a pointer to the
       following structure:

       struct dgvdmcreateinstancepacket
            {
            int               version;
            unsigned int      subdriverid;
            void *            subdriverattributespacketptr;
            unsigned int      persistent          : 1;
            unsigned int      enablediskupdates : 1;
            char              instancename[DGVDMMAXINSTANCENAMELENGTH];
            devt             devicenumber;
            };

       The subdriverid field identifies the subdriver that will manage the
       instance.  The subdriverattributespacketptr field is a pointer to
       a structure defined by the subdriver.  This packet contains



Licensed material--property of copyright holder(s)                         6




vdm(7)                         DG/UX 5.4R3.00                         vdm(7)


       information the subdriver will use to initialize the attributes of
       the newly created instance.  The persistent field indicates whether
       the instance should be stored on disk.  If the field is set to 1, the
       instance will be stored; otherwise, it will only exist in memory and
       will be unable to survive a system reboot.  The enablediskupdates
       field indicates whether changes to an instance should be written to
       disk.  If the field is set to one, all changes to the instance are
       reflected on disk; otherwise, the changes will be limited to the
       memory representation and will not survive a system reboot.  The
       instancename contains the desired name of the instance.  The
       devicenumber field is the only output value in the packet.  This
       field will contain the device number of the instance if it is created
       successfully.

   DGVDMUPDATEINSTANCE
       This command updates an instance. The argument is a pointer to the
       following structure:

       struct dgvdmupdateinstancepacket
           {
           int               version;
           devt             devicenumber;
           unsigned int      updatepersistent          : 1;
           unsigned int      updateenablediskupdates : 1;
           unsigned int      updateinstancename       : 1;
           unsigned int      persistent                 : 1;
           unsigned int      enablediskupdates        : 1;
           char              instancename[DGVDMMAXINSTANCENAMELENGTH];
           };

       The devicenumber is an input field identifying the instance to be
       updated.  When the updatepersistent field is set to 1, the
       persistent field is used to change the instance.  When the
       updateenablediskupdates field is set to 1, the enablediskupdates
       field is used to change the instance.  When the updateinstancename
       field is set to 1, the instancename field is used to update the
       instance.

       Any number of the update fields can be used with a single command.

       The changing of the persistent and enablediskupdates bits can
       result in four possible states:

       Persistent/Writes Enabled         This is the most common state of an
                                         instance.  It is on disk and any
                                         changes to it are reflected on
                                         disk.  Instances in this state are
                                         referred to as persistent.

       Non-persistent/Writes Enabled     The instance is not on disk, but
                                         changes are stored to disk.  Since
                                         there is no data on disk to store,
                                         this combination of settings is
                                         illegal.  Any changes in the



Licensed material--property of copyright holder(s)                         7




vdm(7)                         DG/UX 5.4R3.00                         vdm(7)


                                         persistent or enablediskupdates
                                         fields that result in this state
                                         will cause the command to fail and
                                         errno to be set to EINVAL.

       Persistent/Writes Disabled        The instance is on disk, but any
                                         changes to it are not stored to
                                         disk.  Instances in this state are
                                         referred to as floating.

       Non-persistent/Writes Disabled    The instance is not on disk and no
                                         changes to the instances will be
                                         stored on disk.  Instances in this
                                         state are referred to as temporary.

       The transition of an instance from one state to another results in a
       different set of actions:

       Persistent to Floating            No change is made to the instance
                                         representation on disk, but any
                                         changes to the instance are not
                                         reflected on disk.  The fact that
                                         writes are disabled is not store on
                                         disk and, therefore, not remembered
                                         through system reboots.

       Persistent to Temporary           The instance is taken off of disk,
                                         but will still exist in memory
                                         until it is either deleted or the
                                         system is rebooted.

       Floating to Persistent            The instance is stored to disk.

       Temporary to Persistent           The instance is stored to disk.

   DGVDMUPDATEATTRIBUTES
       This command updates the information the subdriver has stored in the
       instance's attributes area. The argument is a pointer to the
       following structure:

       struct dgvdmupdateattributespacket
            {
            int               version;
            devt             instancedevicenumber;
            unsigned  int     subdriverid;
            void *            subdriverattributespacketptr;
            };

       The instancedevicenumber is an input field containing the device
       number of the instance on which the desired attributes information is
       to be retrieved.  The subdriverid is an input field identifying the
       subdriver that manages the instance.  The purpose of this field is to
       confirm the expected subdriver to avoid the retrieval of information
       that was not expected because the instance changed its managing



Licensed material--property of copyright holder(s)                         8




vdm(7)                         DG/UX 5.4R3.00                         vdm(7)


       subdriver.  The subdriverattributespacketptr is an input field
       that points to a structure defined by the subdriver.

   DGVDMDELETEINSTANCE
       This command deletes an instance. The argument is a pointer to the
       following structure:

       struct dgvdmdeleteinstancepacket
           {
           int               version;
           devt             devicenumber;
           };

       The devicenumber field is an input field.  This field contains the
       device number of the instance being deleted.  If the instance is the
       child of any other instance, the delete request will fail.  If the
       instance is open, the delete request will fail and errno will be set
       to EBUSY.  If the instance is exported but not open, the delete will
       succeed and the device nodes created as a result of the export will
       be removed.

   DGVDMEXPORTINSTANCE
       This command makes an instance available for use by creating device
       nodes in the file system for it. The argument is a pointer to the
       following structure:

       struct dgvdmexportinstancepacket
           {
           int           version;
           devt         devicenumber;
           unsigned int  partiallyexported : 1;
           };

       The devicenumber field identifies the instance to be exported.
       Device nodes of the instance will be created in the device directory
       for virtual disks (the /dev/dsk and /dev/rdsk directories).  An
       attempt is made to create two device nodes in each of the device
       directories.  One device node is the short name containing only the
       ASCII characters supplied when it was created.  The other device node
       is the long name of the instance of the form: vdm(instance-
       name,generation-number,systemid,number).  Because any number of
       instances on a system may have the same short name, only one of the
       instances can have its short name in the export directories.  If
       there is a device node by the short name of the instance being
       exported, only a device node of the long name will be created and the
       partiallyexported will be set to 1; otherwise, if both names are
       successfully created, it is set to 0.

   DGVDMUNEXPORTINSTANCE
       This command removes the device node created by the export command on
       this instance in the /dev/dsk and/dev/rdsk directories. The argument
       is a pointer to the following packet:

       struct dgvdmunexportinstancepacket



Licensed material--property of copyright holder(s)                         9




vdm(7)                         DG/UX 5.4R3.00                         vdm(7)


           {
           int             version;
           devt           devicenumber;
           };

       The devicenumber field identifies the instance to be unexported.
       The device node for an unexported instance will be removed and will
       no longer be recreated on system reboot even if the instance was
       persistent.  This command can be performed while the instance is in
       use.

   DGVDMGETINSTANCEINFO
       This command provides information about a given instance. The
       argument is a pointer to the following packet:

       struct dgvdmgetinstanceinfopacket
           {
           int                       version;
           devt                     devicenumber;
           unsigned int              subdriverid;
           struct dgvdminstanceid instanceid;
           unsigned int              duplicatenumber;
           unsigned int              usable             : 1;
           unsigned int              open               : 1;
           unsigned int              persistent         : 1;
           unsigned int              exported           : 1;
           unsigned int              partiallyexported : 1;
           unsigned int              logging            : 1;
           char                      instancename
                                       [DGVDMMAXINSTANCENAMELENGTH];
           };

       The devicenumber field identifies the instance for which the
       information is being obtained and is the only input field except for
       the version.

       The subdriverid field identifies the subdriver that manages the
       instance.  The instanceid uniquely identifies an instance; however,
       if the physical disk on which the instance resides is copied, then
       the instance may be a duplicate.  The duplicatenumber will be set to
       some value depending on how many other duplicates of this instance
       exist.

       If the open field is set to 1, the instance is currently opened.  If
       the usable field is set to 1, the instance can be opened if it is not
       currently open.  If the persistent field is set to 1, the instance is
       persistent.  If the diskupdatesenabled field is set to 1, the
       instance currently has changes to is stored to disk.  If the exported
       field is set to 1, the instance is currently exported.  If the
       instance is exported and the partiallyexported is set to 1, the
       instance only has its long name in the export directory.  If the
       logging field is set to 1, the instance is currently capturing log
       information.




Licensed material--property of copyright holder(s)                        10




vdm(7)                         DG/UX 5.4R3.00                         vdm(7)


       This command can be performed while the instance is in use.

   DGVDMGETATTRIBUTES
       This command gets the information the subdriver has stored in the
       instance's attributes. The argument is a pointer to the following
       structure:

       struct dgvdmgetattributespacket
            {
            int               version;
            devt             instancedevicenumber;
            unsigned  int     subdriverid;
            void *            subdriverattributespacketptr;
            };

       The instancedevicenumber is an input field containing the device
       number of the instance on when the desired attributes information is
       to be retrieved.  The subdriverid is an input field field
       identifying the subdriver that manages the instance.  The purpose of
       this field is to confirm the expected subdriver to avoid the
       retrieval of information that was not expected because the instance
       changed its managing subdriver.  The subdriverattributespacketptr
       is an input field that is a pointer to a structure defined by the
       subdriver.  This packet will be filled by the subdriver with
       information describing its attributes.

   DGVDMLISTINSTANCES
       This command provides a device number for each instance on the system
       on each call. The argument is a pointer to the following packet:

       struct dgvdmlistinstancespacket
           {
           int             version;
           unsigned int    key;
           unsigned int    available;
           unsigned int    filled;
           unsigned int    numberofinstances.
           devt *         devicenumbers;
           };

       The key field is an input field initialized to 0 when the instances
       are first listed.  The key field is then used by the kernel to
       maintain its place in the list.  This field should only be accessed
       when it is set to 0 to start the listing from the beginning. The
       devicenumbers field is a pointer to the device number entries.
       These entries are filled as a result of the command.  The available
       field is an input field set to the number of available entries
       pointed to by the devicenumbers field. If this field is set to zero,
       no instance information will be returned, however the
       numberofinstances field will be updated the the number of instances
       currently defined in the system. The filled field is an output field
       and is set to the number of entries that were filled in the
       devicenumbers entries. The numberofinstances field is an output
       field set to the number of instances defined on the system.  If there



Licensed material--property of copyright holder(s)                        11




vdm(7)                         DG/UX 5.4R3.00                         vdm(7)


       are no more instances to be listed, the call will fail and the errno
       will be set to ENOENT.

   DGVDMIOCTLSUBDRIVER
       This command issues the given ioctl(2) command to a subdriver.  The
       purpose of this command is to simplify the mechanism used to issue a
       command to a subdriver.  To issue the ioctl(2) command, a device node
       must be open(2)ed.  If no instance of that subdriver exists or an
       instance is not exported, this command is helpful since it only
       requires the /dev/vdm device node to use it.

       struct dgvdmioctlsubdriverpacket
           {
           int             version;
           unsigned int    subdriverid;
           devt           instancedevicenumber;
           int             command;
           int             argument;
           };

       The subdriverid field is an input field identifying the subdriver to
       receive the command.  The instancedevicenumber is an optional
       parameter identifying an instance of the given subdriver.  This
       argument is supplied if the given subdriver indicates that the fd
       argument is required.  If this field is not required, it must be set
       to NODEV.  If the instance is not of the subdriver identified by the
       subdriverid, the command will fail and errno will be set to EINVAL.
       The command and the argument fields are used the same as the
       corresponding ioctl(2) arguments.

   DGVDMINSERTINSTANCE
       This command changes a given instance's function and provides the
       ability to use the instance's old function in its definition of its
       new function. The argument is a pointer to the following packet:

       struct dgvdminsertinstancepacket
           {
           int             version;
           devt           instancetochange;
           devt           dummyinstance;
           unsigned int    subdriverid;
           void *          attributespacketptr;
           };

       The instancetochange will have its function pushed on to the
       dummyinstance which must be a dummy instance (see vdmdummy(7)).  The
       instancetochange will take on the new function defined by the
       subdriverid and the attributespacketptr.  These fields are
       identical to those by the same in in the DGVDMCREATEINSTANCE.
       This command can be performed while the instancetochange is open.

   DGVDMEXTRACTINSTANCE
       This command provides the removal of a given instance's function by
       collapsing its child's function onto it. The argument is a pointer to



Licensed material--property of copyright holder(s)                        12




vdm(7)                         DG/UX 5.4R3.00                         vdm(7)


       the following packet:

       struct dgvdmextractinstancepacket
           {
           int             version;
           devt           parentdevicenumber;
           devt           newparentdevicenumber;
           };

       The parentdevicenumber field is an input field identifying the
       instance whose function is to be extracted.  This instance will take
       on the function of its child.  The parentdevicenumber must have
       only one child and be the same size as that child.

       The newparentdevicenumber is an input field identifying the
       instance that will take on the parentdevicenumber's function. The
       newparentdevicenumber must be a dummy instance (see vdmdummy(7)).

       The child of the instance identified by parentdevicenumber will
       become a dummy instance and be a child of the instance identified by
       newparentdevicenumber.  The newparentdevicenumber and its child
       can be deleted after the extract operation completes.

       This command can be performed while the parentdevicenumber is in
       use.

   DGVDMLINKCHILDINSTANCE
       This command adds a child instance to a given parent instance. The
       argument is a pointer to the following packet:

       struct dgvdmlinkchildinstancepacket
           {
           int             version;
           devt           parentdevicenumber;
           unsigned int    parentsubdriverid;
           devt           childdevicenumber;
           void *          childpacketptr;
           };

       The parentdevicenumber field is an input field and identifies the
       instance to which the child should be added.  The parentsubdriverid
       is an input field and should be set to the subdriver ID of the
       parent.  The childdevicenumber field is an input field identifying
       the child to be added to the parent. The childpacketptr is a
       pointer to a subdriver defined packet that allows the parent's
       subdriver to describe the role the child plays on the parent.

       Whether this command is allowed when the instance identified by
       parentdevicenumber or the childdevicenumber is open is left to
       each subdriver to decide.

   DGVDMGETCHILDINSTANCE
       This command provides a device number for each child instance on a
       given parent instance. The argument is a pointer to the following



Licensed material--property of copyright holder(s)                        13




vdm(7)                         DG/UX 5.4R3.00                         vdm(7)


       packet:

       struct dgvdmgetchildinstancepacket
           {
           int                                   version;
           unsigned int                          key;
           devt                                 parentdevicenumber;
           unsigned int                          parentsubdriverid;
           unsigned int                          available;
           unsigned int                          filled;
           unsigned int                          numberofchildren;
           struct dgvdmchildinstancepacket * childinstancearrayptr;
           };

       The key field is an input field set to 0 when the children are first
       listed.  The key field is then used by the kernel to maintain its
       place in the list.  This field should only be accessed when it is set
       to 0 to start the listing from the beginning. The
       parentdevicenumber field is an input field and identifies the
       instance for which the children should be listed. Because the packet
       is subdriver specific, the parentsubdriverid is used to confirm the
       subdriver expected to retrieve the role packet described above.  The
       available field is an input field that identifies the number of
       dg_vdm_child_instance_packets that are available to receive data back
       about each child. If the value of this field is zero, then no child
       information is returned. However, the numberofchildren output field
       is always updated with the total number of children of the given
       parent instance. The filled output field contains the number of
       dg_vdm_child_instance_packets returned. The childinstancearrayptr
       is a pointer to an array of dg_vdm_child_instance_packet structures
       that are available for data to be returned in.

       When there are no more children to be listed, the call will fail and
       errno will be set to ENOENT.

       The following packet is used to make an array of packets pointed to
       by the child_instance_array_ptr in the
       dg_vdm_get_child_instance_packet:

       struct dgvdmchildinstancepacket
           {
           void *                               childrolepacketptr;
           struct dgvdminstancespecifier      childinstance;
           unsigned int                         childsubdriverid;
           };

       The childinstance field is an output field identifying one of the
       parent's children on each call.

       The childsubdriverid is an output field set to the subdriver ID of
       the child returned.  Since the child returned by the Physical
       Subdriver is not a VDM instance, the childsubdriverid is set to
       DGVDMSUBDRIVERIDOFANONVDMDEVICE.  The childsubdriverid is
       set to DGVDMNOSUBDRIVERID when the instance specifier uses the id



Licensed material--property of copyright holder(s)                        14




vdm(7)                         DG/UX 5.4R3.00                         vdm(7)


       field, indicating that the child is missing.

       The childrolepacketptr is a pointer to a packet defined by the
       subdriver of the parent.  When this pointer is not NULL, the contents
       of the packet are filled by the parent subdriver describing the role
       the child plays on it.  If the childrolepacketptr field is set to
       NULL, then the subdriver will not attempt to fill the packet with the
       role information.  In this case, the parentsubdriverid is not
       required to be set.

   DGVDMGETPARENTINSTANCE
       This command provides a device number for each parent instance of a
       given child instance. The argument is a pointer to the following
       packet:

       struct dgvdmgetparentinstancepacket
           {
           int                                    version;
           unsigned int                           key;
           devt                                  childdevicenumber;
           unsigned int                           available;
           unsigned int                           filled;
           unsigned int                           numberofparents;
           struct dgvdmparentinstancepacket * parentinstancearrayptr;
           };

       The key field is an input field initialized to 0 when the parents are
       first listed.  The key field is then used by the kernel to maintain
       its place in the list.  This field should only be accessed when it is
       initially set to start the listing from the beginning. The
       childdevicenumber field is an input field and identifies the
       instance for which the parents should be listed.  The available field
       is an input field that identifies the number of
       dg_vdm_parent_instance_packets that are available to receive data
       back about each parent. If the value of this field is zero, then no
       parent information is returned. However, the numberofparents output
       field is always updated with the total number of parents of the given
       instance. The filled output field contains the number of
       dg_vdm_parent_instance_packets returned. The childinstancearrayptr
       is a pointer to an array of dg_vdm_child_instance_packet structures
       that are available for data to be returned in.

       The following packet is used to make an array of packets pointed to
       by the parent_instance_array_ptr in the
       dg_vdm_get_parent_instance_packet:

       struct dgvdmparentinstancepacket
           {
           devt               parentdevicenumber;
           unsigned int        parentsubdriverid;
           };

        The parentdevicenumber field is an output field identifying one of
       the child's parents on each call.  The parentsubdriverid field is



Licensed material--property of copyright holder(s)                        15




vdm(7)                         DG/UX 5.4R3.00                         vdm(7)


       an output field and contains the subdriver ID of the parent returned
       in the parentdevicenumber field.

   DGVDMUNLINKCHILDINSTANCE
       This command removes a child from a given parent instance.  This
       change is intended to be permanent. The argument is a pointer to the
       following packet:

       struct dgvdmunlinkchildinstancepacket
           {
           int                              version;
           devt                            parentdevicenumber;
           struct dgvdminstancespecifier  childinstance;
           };

       The parentdevicenumber field is an input field and identifies the
       instance from which a child should be deleted. The childinstance
       field is an input field identifying the child to be unlinked from the
       parent (see the Instance Specification section above).

   DGVDMREGISTERDISK
       This command introduces a DG/UX formatted disk to be read by the
       kernel.  The kernel reads an on-disk database that describes
       instances that are persistent and have some portion of their data
       residing on the given disk.  Any persistent instances that were also
       exported will have their device nodes created. As a result of the
       registration, a physical instance for the given physical device is
       created.  In addition, a number of partitions (see vdmpart(7)) will
       automatically be created for the system managed data on disk.
       Therefore, any further use of free space on the given physical drive
       must be accessed through the allocation of the drive's free space
       from the Partition Subdriver. The argument is a pointer to the
       following packet:

       struct dgvdmregisterdiskpacket
           {
           int             version;
           unsigned int    numberofdisks;
           devt *         diskarrayptr;
           unsigned int    anypartialexports  : 1;
           unsigned int    anyfailedrecreates : 1;
           };

       The numberofdisks field is an input field identifying the number of
       elements in the diskarrayptr array.  The diskarrayptr is a
       pointer to the device numbers of the disks to be registered.

       The anypartialexports field is an output field.  It is set to 1 if
       any of the instances created as a result of the registration failed
       to export both the long name and the short name.

       The anyfailedrecreates field is an output field.  It is set to 1 if
       any instance failed to recreate from the registration.




Licensed material--property of copyright holder(s)                        16




vdm(7)                         DG/UX 5.4R3.00                         vdm(7)


   DGVDMDEREGISTERDISK
       This command removes from memory all instances that have some portion
       of their data residing on the given disk. The argument is a pointer
       to the following packet:

       struct dgvdmderegisterdiskpacket
           {
           int             version;
           devt           physicaldevicenumber;
           };

       The physicaldevicenumber field is an input field and identifies the
       physical disk to be deregistered.

   DGVDMLISTREGISTEREDDISKS
       This command returns the disks currently registered by the VDM. The
       argument is a pointer to the following packet:

       struct dgvdmlistregistereddiskspacket
           {
           int             version;
           unsigned int    key;
           unsigned int    available;
           unsigned int    filled;
           unsigned int    numberofregistereddisks;
           devt *         physicaldevicenumber;
           };

       The key field is an input field set to 0 when the disks are first
       listed.  The key field is then used by the kernel to maintain its
       place in the list.  This field should only be accessed when it is set
       to 0 to start the listing from the beginning.  The
       numberofregistereddisks is an output field that is always set to
       the total number of registered disks. The physicaldevicenumber
       field is a pointer to an array of device numbers.  The available
       field is an input value that is the number of available elements in
       the physicaldevicenumber field.  The filled field is an output
       field that will contain the number of elements placed in the
       physicaldevicenumber array.

       If the available field is set to 0, then the physicaldevicenumber
       array will not be filled, but the numberofregistereddisks will be
       set appropriately.

       When there are no more registered physical disks to be listed, the
       call will fail and errno will be set to ENOENT.

   DGVDMLISTSUBDRIVERS
       This command returns the subdrivers currently available on the
       system.  The argument is a pointer to the following packet:

       struct dgvdmlistsubdriverspacket
           {
           int             version;



Licensed material--property of copyright holder(s)                        17




vdm(7)                         DG/UX 5.4R3.00                         vdm(7)


           unsigned int    key;
           unsigned int    available;
           unsigned int    filled;
           unsigned int    numberofsubdrivers;
           unsigned int *  subdriverid;
           };

       The key field is an input field set to 0 when the subdrivers are
       first listed.  The key field is then used by the kernel to maintain
       its place in the list.  This field should only be accessed when it is
       set to 0 to start the listing from the beginning.  The
       numberofsubdriver is an output field that is always set to the
       total number of subdrivers available. The subdriverid field is a
       pointer to an array of subdriver ID's.  The available field is an
       input value that is the number of available elements in the
       subdriverid array.  The filled field is an output field that will
       contain the number of elements placed in the subdriverid array.

       If the available field is set to 0, then the subdriverid array will
       not be filled, but the numberofregistereddisks will be set
       appropriately.

       When there are no more subdrivers to be listed, the call will fail
       and errno will be set to ENOENT.

   DGVDMGETCHANGETICKET
       This command returns a ticket that can be used to determine if an
       ioctl(2) command (other than this one) was issued to the VDM since
       the the last time this call was made.  The argument is a pointer to
       the following packet:

       struct dgvdmgetchangeticketpacket
           {
           int             version;
           int             changeticket;
           };

       The changeticket field is an output field that contains a value that
       can be compared to the value obtained from a previous call.  If the
       values are different, that means that an ioctl(2) command was issued
       to the VDM (other than this one).

   DGVDMGETSUBDRIVERINFO
       This command returns information associated with a given subdriver.
       The argument is a pointer to the following packet:

       struct dgvdmgetsubdriverinfopacket
           {
           int             version;
           unsigned int    subdriverid;
           char            subdriverdevicename
                              [DGVDMMAXSUBDRIVERNAMELENGTH];
           char            subdriverfriendlyname
                              [DGVDMMAXSUBDRIVERNAMELENGTH];



Licensed material--property of copyright holder(s)                        18




vdm(7)                         DG/UX 5.4R3.00                         vdm(7)


           unsigned int    instancecount;
           unsigned int    logging : 1;
           };

       The subdriverid field is an input field and identifies one of the
       available subdrivers.  The subdriverdevicename is an output field
       containing the subdriver's device name (every subdriver is a device
       driver).  The subdriverfriendlyname is an output field containing
       the string describing the subdriver's functionality in user-friendly
       terms.  The instancecount field is an output field indicating the
       current number of instances managed by this subdriver.  The logging
       field is an output field indicating that logging has been enabled for
       all instances of this particular subdriver.

       It is a convention that the friendly name be returned contain all
       lower case letters.

       If the subdriver identified with the subdriverid does not exist or
       is not configured into the system, the call will fail and errno will
       be set to ENXIO.

   DGVDMLOGPACKET
       This command enables and disables the logging of I/O information on a
       per instance and a per subdriver basis.  The argument is a pointer to
       the following packet:

       struct dgvdmlogpacket
           {
           int             version;
           int             logging : 1;
           unsigned int    numberofinstances;
           devt *         instancearrayptr;
           unsigned int    numberofsubdrivers;
           unsigned int *  subdriverarrayptr;
           };

       If the logging field is set to 1, then logging is enabled for the
       given instances and subdrivers; otherwise, logging is disabled.

       The numberofinstances indicates the number of elements in the
       instancearrayptr which points to a set of devices numbers
       corresponding to the instances to be affected.

       The numberofsubdrivers indicates the number of elements in the
       subdriverarrayptr which points to a set of subdriver ID's.  When a
       subdriver is supplied, all instances managed by that subdriver will
       have its logging enabled or disabled.

   DGVDMSETBOOTINFOPACKET
       This command causes an entry to be stored on the given disk.  This
       entry is read from the disk during system initialization to determine
       what virtual disk should be used for the root and swap (the
       /etc/fstab, which can contain this information, is not yet available
       because it resides in the root file system.



Licensed material--property of copyright holder(s)                        19




vdm(7)                         DG/UX 5.4R3.00                         vdm(7)


       This provides the ability to have a different root and swap virtual
       disk depending on the disk drive from which you boot.  Although this
       does not require that the disk on which the information is stored
       contain the root and swap disk.  In this way, you can place the root
       and swap information on multiple drives for redundancy.  Also, a
       different root, but common swap can be specified for each disk.  This
       is helpful since the root file system may vary when this mechanism is
       used, but the swap may not.

       The argument is a pointer to the following packet:

       struct dgvdmsetbootinfopacket
           {
           int             version;
           devt           diskdevicenumber;
           unsigned int    setdefaultroot     : 1;
           unsigned int    setdefaultswap     : 1;
           devt           defaultroot;
           devt           defaultswap;
           };

       All fields are input fields.

       The diskdevicenumber field should be the device number of a
       registered disk (not the physical instance created for that disk).

       If the setdefaultroot field is set to 1, the device number in the
       defaultroot field is used to identify the virtual disk containing
       the file system that should be used as the root file system the next
       time the system is boot from the given disk device.  Supplying NODEV
       for the device number will have the effect of clearing the current
       default root setting.  If the, setdefaultroot field is not set to
       1, the default root for this disk is left with its current setting.

       If the setdefaultswap field is set to 1, the device number in the
       defaultswap field is used to identify a virtual disk available for
       swapping the next time the system is boot from the given disk device.
       Supplying NODEV for the device number will have the effect of
       clearing the current default swap setting. If the, setdefaultswap
       field is not set to 1, the default swap for this disk is left with
       its current setting.

   DGVDMGETBOOTINFO
       This command gets the root or swap disk specified for the given disk
       device. The argument is a pointer to the following packet:

       struct dgvdmgetbootinfopacket
           {
           int             version;
           devt           diskdevicenumber;
           unsigned int    defaultrootset : 1;
           unsigned int    defaultswapset : 1;
           struct dgvdminstancespecifier
                           defaultroot;



Licensed material--property of copyright holder(s)                        20




vdm(7)                         DG/UX 5.4R3.00                         vdm(7)


           struct dgvdminstancespecifier
                           defaultswap;
           };

       The diskdevicenumber is an input field and is set to the device
       number of the disk device (not the physical instance created for the
       device) from which the boot information should be obtained.  This
       device must be a registered disk to perform this operation.

       If the defaultrootset field is set to 1, the defaultroot instance
       specifier is set, indicating that there is a default root setting for
       this physical device.

       If the defaultswapset field is set to 1, the defaultswap instance
       specifier is set, indicating that there is a default swap setting for
       this physical device.

       The defaultroot and defaultswap fields are specifiers because the
       default value may be for a existing virtual disk (the specifier would
       indicate that a device number was used) or a virtual disk that was
       currently not in existence (the specifier would indicate that a
       device number was not used and therefore the ID must be used).  The
       most common reason a a virtual disk does not currently exist is
       because it exists on a device that is currently not registered.

EXAMPLE
       #include <errno.h>
       #include <fcntl.h>
       #include <stdio.h>
       #include <string.h>
       #include <sys/stat.h>
       #include <sys/dgsysctl.h>
       #include <sys/ioctl.h>
       #include <unistd.h>

       /*
        *  These macros initialize given packets by zeroing the bytes
        *  contained in the packet and setting the version field.  The
        *  first macro initializes the packets described in the vdm(7)
        *  man page.  The second initiliazes the packets described in the
        *  vdmphys(7) man page.  The third initilizes the packets described
        *  in the vdmmirr(7) man page.
        */
       #define vdminitpacket(p) \
            (bzero((char *)&p, sizeof(p)), \
             p.version = DGVDMIOCTLPACKETVERSION0);

       #define vdmphysinitpacket(p) \
            (bzero((char *)&p, sizeof(p)), \
             p.version = DGVDMPHYSIOCTLPACKETVERSION0);

       #define vdmmirrinitpacket(p) \
            (bzero((char *)&p, sizeof(p)), \
             p.version = DGVDMMIRRIOCTLPACKETVERSION0);



Licensed material--property of copyright holder(s)                        21




vdm(7)                         DG/UX 5.4R3.00                         vdm(7)


       /***********************************************************************
        *  This function returns the device number for a given instance.
        ***********************************************************************/
       int vdminstancenametodevice (
       char *  instancename,
       devt * devicenumberptr
                                       )
       {
       int                             status;
       char                            devicename[DGSYSCTLMAXNAMELENGTH];
       struct dgsysctlnametodevice nametodevicepkt;

       sprintf(devicename, "vdm(%s)", instancename);
       nametodevicepkt.devicename = devicename;
       status = dgsysctl(DGSYSCTLNAMETODEVICE, &nametodevicepkt);
       if (status == -1)
           {
           return (status);
           }
       *devicenumberptr = nametodevicepkt.devicenumber;
       return (0);
       }

       /***********************************************************************
        *  This function returns the device number for a given instance.
        ***********************************************************************/
       int vdminstancedevicetoname (
       devt   devicenumber,
       char *  instancename
                                       )
       {
       int                             status;
       char                            devicename[DGSYSCTLMAXNAMELENGTH];
       struct dgsysctldevicetoname devicetonamepkt;

       devicetonamepkt.devicenumber = devicenumber;
       devicetonamepkt.devicename = devicename;
       devicetonamepkt.maxnamelength = DGSYSCTLMAXNAMELENGTH;
       status = dgsysctl(DGSYSCTLDEVICETONAME, &devicetonamepkt);
       if (status == -1)
           {
           return (status);
           }
       if (strncmp(devicetonamepkt.devicename, "vdm", 3) == 0)
           {
           strcpy(instancename, devicetonamepkt.devicename + 4);
           }
       else
           {
           strcpy(instancename, devicetonamepkt.devicename);
           }
       return (0);
       }




Licensed material--property of copyright holder(s)                        22




vdm(7)                         DG/UX 5.4R3.00                         vdm(7)


       /***********************************************************************
        *  This function to issues an ioctl(2) to the /dev/vdm device node.
        *  The device node is only opened once and the static causes it to be
        *  remembered from call to call.  The device node will get closed when
        *  the process exits.
        ***********************************************************************/
       int vdmioctl (
       int command,
       int argument
                     )
       {
       static int fd = -1;

       if (fd == -1)
           {
           fd = open("/dev/vdm", ORDONLY);
           if (fd < 0)
               {
               return (-1);
               }
           }
       return(ioctl(fd, command, argument));
       }

       /***********************************************************************
        *  This function issues a subdriver specific call to a subdriver.
        ***********************************************************************/
       int vdmioctlsubdriver  (
       unsigned int subdriverid,
       devt        instance,
       int          command,
       int          argument
                                )
       {
       struct dgvdmioctlsubdriverpacket ioctlpkt;

       vdminitpacket(ioctlpkt);
       ioctlpkt.subdriverid             = subdriverid;
       ioctlpkt.instancedevicenumber  = instance;
       ioctlpkt.command                 = command;
       ioctlpkt.argument                = argument;

       return (vdmioctl(DGVDMIOCTLSUBDRIVER, (int)&ioctlpkt));
       }

       /***********************************************************************
        *  This function creates a non-persistent instance of a given subdriver
        *  type.
        ***********************************************************************/
       devt vdmcreateinstance (
       char *       instancename,
       unsigned int subdriverid,
       void *       attributesptr
                        )



Licensed material--property of copyright holder(s)                        23




vdm(7)                         DG/UX 5.4R3.00                         vdm(7)


       {
       int                                  status;
       struct dgvdmcreateinstancepacket createpkt;

       vdminitpacket(createpkt);
       createpkt.subdriverid = subdriverid;
       createpkt.subdriverattributespacketptr = attributesptr;
       createpkt.persistent = 1;
       createpkt.enablediskupdates = 1;
       strcpy(createpkt.instancename, instancename);

       status = vdmioctl(DGVDMCREATEINSTANCE, (int)&createpkt);
       if (status == -1)
           {
           return (NODEV);
           }
       else
           {
           return (createpkt.devicenumber);
           }
       }

       /***********************************************************************
        *  This function deletes an instance identified by its device number.
        ***********************************************************************/
       devt vdmdeleteinstancedevice (
       devt devicenumber
                               )
       {
       int                                  status;
       struct dgvdmdeleteinstancepacket deletepkt;

       vdminitpacket(deletepkt);
       deletepkt.devicenumber = devicenumber;
       status = vdmioctl(DGVDMDELETEINSTANCE, (int)&deletepkt);
       return (status);
       }

       /***********************************************************************
        *  This function deletes an instance identified by its name.
        ***********************************************************************/
       devt vdmdeleteinstance (
       char * instancename
                        )
       {
       devt devicenumber;
       int   status;

       status = vdminstancenametodevice(instancename, &devicenumber);
       if (status != 0)
           {
           return (status);
           }
       status = vdmdeleteinstancedevice(devicenumber);



Licensed material--property of copyright holder(s)                        24




vdm(7)                         DG/UX 5.4R3.00                         vdm(7)


       return (status);
       }

       /***********************************************************************
        *  This function exports an instance identified by its device number.
        ***********************************************************************/
       devt vdmexportinstancedevice (
       devt        devicenumber
                               )
       {
       int                                  status;
       struct dgvdmexportinstancepacket exportpkt;

       vdminitpacket(exportpkt);
       exportpkt.devicenumber = devicenumber;
       status = vdmioctl(DGVDMEXPORTINSTANCE, (int)&exportpkt);
       if (exportpkt.partiallyexported)
           {
           fprintf(stderr, "Warning: instance is only partially exported\n");
           }
       return (status);
       }

       /***********************************************************************
        *  This function exports an instance identified by its device number.
        ***********************************************************************/
       devt vdmunexportinstancedevice (
       devt        devicenumber
                               )
       {
       int                                    status;
       struct dgvdmunexportinstancepacket unexportpkt;

       vdminitpacket(unexportpkt);
       unexportpkt.devicenumber = devicenumber;
       status = vdmioctl(DGVDMUNEXPORTINSTANCE, (int)&unexportpkt);
       return (status);
       }

       /***********************************************************************
        *  This function exports an instance identified by its name.
        ***********************************************************************/
       devt vdmexportinstance (
       char *          instancename
                        )
       {
       devt devicenumber;
       int   status;

       status = vdminstancenametodevice(instancename, &devicenumber);
       if (status != 0)
           {
           return (status);
           }



Licensed material--property of copyright holder(s)                        25




vdm(7)                         DG/UX 5.4R3.00                         vdm(7)


       status = vdmexportinstancedevice(devicenumber);
       return (status);
       }

       /***********************************************************************
        *  This function unexports an instance identified by its name.
        ***********************************************************************/
       devt vdmunexportinstance (
       char *          instancename
                        )
       {
       devt devicenumber;
       int   status;

       status = vdminstancenametodevice(instancename, &devicenumber);
       if (status != 0)
           {
           return (status);
           }
       status = vdmunexportinstancedevice(devicenumber);
       return (status);
       }

       /***********************************************************************
        *  This function updates the attributes associated with a given instance.
        ***********************************************************************/
       int vdmupdateinstanceattributes (
       devt        instancedevicenumber,
       unsigned int subdriverid,
       void *       subdriverpacketptr
                                 )
       {
       int                                    status;
       struct dgvdmupdateattributespacket updateattributespkt;

       vdminitpacket(updateattributespkt);
       updateattributespkt.instancedevicenumber = instancedevicenumber;
       updateattributespkt.subdriverid = subdriverid;
       updateattributespkt.subdriverattributespacketptr = subdriverpacketptr;
       status = vdmioctl(DGVDMUPDATEATTRIBUTES, (int)&updateattributespkt);
       return (status);
       }

       /***********************************************************************
        *  This function updates the attributes associated with a given instance.
        ***********************************************************************/
       int vdmregisterdisk (
       char *       devicename
                             )
       {
       int                                         status;
       struct dgsysctlnametodevice             nametodevicepkt;
       struct dgvdmregisterdiskpacket          registerpacket;




Licensed material--property of copyright holder(s)                        26




vdm(7)                         DG/UX 5.4R3.00                         vdm(7)


       nametodevicepkt.devicename = devicename;
       status = dgsysctl(DGSYSCTLNAMETODEVICE, &nametodevicepkt);
       if (status == -1)
           {
           return (status);
           }

       vdminitpacket(registerpacket);
       registerpacket.numberofdisks = 1;
       registerpacket.diskarrayptr = &nametodevicepkt.devicenumber;
       status = vdmioctl(DGVDMREGISTERDISK, (int)&registerpacket);
       return (status);
       }

       /***********************************************************************
        *  This function opens a device with a given device number.
        ***********************************************************************/
       int
       vdmopendevice(devt devicenumber, int openflag, int protectionmode)
       {
       int       status;
       int       devicedesc;
       char      temppath[]="/dev/.XXXXXX";

       mktemp(temppath);
       if (strcmp(temppath, "") == 0)
           {
           return (-1);
           }

       status = mknod(temppath, SIFCHR | SIRUSR | SIWUSR, devicenumber);
       if (status != 0)
           {
           devicedesc = status;
           goto cleanup;
           }

       devicedesc = open(temppath, openflag, protectionmode);

       cleanup:

       unlink(temppath);
       return (devicedesc);
       }

       /***********************************************************************
        *  This function gets the size of a given disk using the file descriptor.
        ***********************************************************************/
       int
       vdmgetdisksize(int diskdesc, long *blocksptr)
       {
       int           status;
       struct dskget dskgetbuf;




Licensed material--property of copyright holder(s)                        27




vdm(7)                         DG/UX 5.4R3.00                         vdm(7)


       status = ioctl(diskdesc, DSKIOCGET, (int)&dskgetbuf);
       if (status < 0)
           {
           return (status);
           }

       *blocksptr = (dskgetbuf.bytespersector / 512) * dskgetbuf.totalsectors;
       return (0);
       }

       /***********************************************************************
        *  This is the example routine.
        ***********************************************************************/
       int vdmexample (void)
       {
       int                                        fd;
       int                                        i;
       int                                        status;
       devt                                      adevicenumber;
       devt                                      bdevicenumber;
       devt                                      cdevicenumber;
       devt                                      ddevicenumber;
       struct dgvdmdeleteinstancepacket       deleteinstancepkt;
       struct dgvdminsertinstancepacket       insertinstancepkt;
       struct dgvdmextractinstancepacket      extractinstancepkt;
       struct dgvdmlinkchildinstancepacket   linkchildpkt;
       struct dgvdmunlinkchildinstancepacket unlinkchildpkt;
       struct dgvdmphyscreatepacket            createphyspkt;
       struct dgvdmmirrcreatepacket            createmirrpkt;
       struct dskget                              dskgetpkt;
       struct dgsysctlnametodevice            nametodevicepkt;

       /*
        *  To create a physical instance, get the device number of a physical
        *  device on the system.  For more about physical instances, see
        *  vdmphys(7).
        */
       nametodevicepkt.devicename = "sd(insc(),0)";
       status = dgsysctl(DGSYSCTLNAMETODEVICE, &nametodevicepkt);
       if (status == -1)
           {
           perror("sd(insc(),0)");
           exit(1);
           }

       /*
        *  Now, create a physical instance for the above physical device.
        */
       vdmphysinitpacket(createphyspkt);
       createphyspkt.childdevicenumber = nametodevicepkt.devicenumber;
       adevicenumber = vdmcreateinstance(
                      "a", DGVDMPHYSSUBDRIVERID, &createphyspkt);
       if (adevicenumber == NODEV)
           {



Licensed material--property of copyright holder(s)                        28




vdm(7)                         DG/UX 5.4R3.00                         vdm(7)


           perror("create a");
           exit(1);
           }

       /*
        *  For the purposes of example, compare the device number returned in the
        *  creation packet to the one returned from dgsysctl(2).
        */
       nametodevicepkt.devicename = "vdm(a)";
       status = dgsysctl(DGSYSCTLNAMETODEVICE, &nametodevicepkt);
       if (status == -1)
           {
           perror("vdm(a)");
           exit(1);
           }

       if (nametodevicepkt.devicenumber != adevicenumber)
           {
           fprintf(stderr, "Error: The device numbers do not match\n");
           exit(1);
           }

       /*
        *  Export the instance using its instance name.
        */
       status = vdmexportinstancedevice(
            adevicenumber);
       if (status == -1)
           {
           perror("export a");
           exit(1);
           }

       /*
        *  Open the instance and try to delete it.  An error should indicate
        *  that the instance is busy.
        */
       fd = open("/dev/dsk/a", ORDONLY);
       if (fd < 0)
           {
           perror("open a");
           exit(1);
           }

       status = vdmdeleteinstancedevice(adevicenumber);
       if (status == 0 || (status == -1 && errno != EBUSY))
           {
           fprintf(stderr, "Error: Instance 'a' was not busy as expected\n");
           exit(1);
           }

       /*
        *  Get the size of the physical instance.  First get the size using
        *  an ioctl on the file descriptor of the exported instance.  Then use



Licensed material--property of copyright holder(s)                        29




vdm(7)                         DG/UX 5.4R3.00                         vdm(7)


        *  the vdmioctlsubdriver() call to demonstrate how that call is used.
        */
       status = ioctl(fd, DSKIOCGET, &dskgetpkt);
       if (status == -1)
           {
           perror("size of a");
           exit(1);
           }

       /*
        *  Now get the size using the DGVDMIOCTLSUBDRIVER.  If an instance
        *  is not exported and open, this command is useful.
        */
       status = vdmioctlsubdriver(
                 DGVDMPHYSSUBDRIVERID,
                 adevicenumber,
                 DSKIOCGET,
                 (int)&dskgetpkt);
           {
           perror("size of a");
           exit(1);
           }

       /*
        *  Create a dummy instance (see vdmdummy(7)).
        */
       bdevicenumber = vdmcreateinstance("b", DGVDMDUMMYSUBDRIVERID, NULL);
       if (bdevicenumber == NODEV)
           {
           perror("create b");
           exit(1);
           }

       /*
        *  Create a mirror instance (see vdmmirr(7)) on the existing physical
        *  instance.  The dummy instance will take on the functionality of the
        *  physical instance, leaving the following structure:
        *
        *               Before                After
        *      a (physical)  b (dummy)     a (mirror)
        *      |                           |
        *     Disk                         b (physical)
        *                                  |
        *                                 Disk
        *
        */
       vdminitpacket(insertinstancepkt);
       vdmmirrinitpacket(createmirrpkt);
       createmirrpkt.numberofimages = 1;
       createmirrpkt.imagedevicenumbers[0] = bdevicenumber;
       insertinstancepkt.instancetochange = adevicenumber;
       insertinstancepkt.dummyinstance = bdevicenumber;
       insertinstancepkt.subdriverid = DGVDMMIRRSUBDRIVERID;
       insertinstancepkt.attributespacketptr = &createmirrpkt;



Licensed material--property of copyright holder(s)                        30




vdm(7)                         DG/UX 5.4R3.00                         vdm(7)


       status = vdmioctl(DGVDMINSERTINSTANCE, (int)&insertinstancepkt);
       if (status == -1)
           {
           perror("insert");
           exit(1);
           }

       /*
        *  The mirror that was created is not very interesting because it contains
        *  only one image.  To add another image on to the mirror, a child is
        *  linked to the instance.  First, a child must be created to link and
        *  then the child will be linked.  This child will be another SCSI drive
        *  on the system.  It is assumed that the two drives are identical in size.
        */
       nametodevicepkt.devicename = "sd(insc(),1)";
       status = dgsysctl(DGSYSCTLNAMETODEVICE, &nametodevicepkt);
       if (status == -1)
           {
           perror("sd(insc(),1)");
           exit(1);
           }

       vdmphysinitpacket(createphyspkt);
       createphyspkt.childdevicenumber = nametodevicepkt.devicenumber;
       cdevicenumber = vdmcreateinstance(
                      "c", DGVDMPHYSSUBDRIVERID, &createphyspkt);
       if (cdevicenumber == NODEV)
           {
           perror("create c");
           exit(1);
           }

       /*
        *  Now link, as a child, the instance 'c' to the mirror instance 'a'.
        */
       vdminitpacket(linkchildpkt);
       linkchildpkt.parentdevicenumber = adevicenumber;
       linkchildpkt.parentsubdriverid = DGVDMMIRRSUBDRIVERID;
       linkchildpkt.childdevicenumber = cdevicenumber;
       linkchildpkt.childpacketptr = NULL;

       status = vdmioctl(DGVDMLINKCHILDINSTANCE, (int)&linkchildpkt);
       if (status == -1)
           {
           perror("link c to a");
           exit(1);
           }

       /*
        *  Now unlink image 'c' from the mirror by using the unlink child command.
        */
       vdminitpacket(unlinkchildpkt);
       unlinkchildpkt.parentdevicenumber = adevicenumber;
       unlinkchildpkt.childinstance.devicenumberused = 1;



Licensed material--property of copyright holder(s)                        31




vdm(7)                         DG/UX 5.4R3.00                         vdm(7)


       unlinkchildpkt.childinstance.specifiervalue.devicenumber = cdevicenumber;

       status = vdmioctl(DGVDMUNLINKCHILDINSTANCE, (int)&unlinkchildpkt);
       if (status == -1)
           {
           perror("unlink c from a");
           exit(1);
           }

       /*
        *  Now get rid of the mirror instance by first creating a dummy
        *  instance to hold the functionality that is being extracted out.
        *  Below is a diagram of the instances as they currently exist (before)
        *  and how they will exist after the extract (after).
        *
        *               Before                      After
        *
        *         a (mirror)   d (dummy)     a (physical)   d (mirror)
        *         |                          |              |
        *         b (physical)              Disk            b (dummy)
        *         |
        *        Disk
        *
        */
       ddevicenumber = vdmcreateinstance("d", DGVDMDUMMYSUBDRIVERID, NULL);
       if (ddevicenumber == NODEV)
           {
           perror("create d");
           exit(1);
           }

       extractinstancepkt.parentdevicenumber = adevicenumber;
       extractinstancepkt.newparentdevicenumber = ddevicenumber;

       status = vdmioctl(DGVDMEXTRACTINSTANCE, (int)&extractinstancepkt);
       if (status == -1)
           {
           perror("extract");
           exit(1);
           }

       /*
        *  Now instance d and b can be deleted (a single image mirror of a
        *  dummy instance is not very useful).  Image d must be deleted before
        *  b because be is in use as a child of image d.
        */
       status = vdmdeleteinstancedevice(ddevicenumber);
       if (status == -1)
           {
           perror("cleanup d");
           exit(1);
           }
       status = vdmdeleteinstancedevice(bdevicenumber);
       if (status == -1)



Licensed material--property of copyright holder(s)                        32




vdm(7)                         DG/UX 5.4R3.00                         vdm(7)


           {
           perror("cleanup b");
           exit(1);
           }
       }


FILES
SEE ALSO
       dgsysctl(2), vdmphys(7), vdmpart(7), vdmaggr(7), vdmmirr(7),
       vdmremap(7), vdmmpio(7), ioctl(2), dgexterrno(2), iso-88591(5)














































Licensed material--property of copyright holder(s)                        33


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