Museum

Home

Lab Overview

Retrotechnology Articles

Online Manuals

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

Media Vault

Software Library

Restoration Projects

Artifacts Sought

Related Articles

vdm(7)

vdmphys(7)

vdmpart(7)

ioctl(2)



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


NAME
       vdmmirr - Mirror Subdriver of the Virtual Disk Manager

SYNOPSIS
       #include <types.h>
       #include <ioctl.h>

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

DESCRIPTION
       The Mirror Subdriver is a pseudo-device driver that works under the
       Virtual Disk Management (VDM) framework (see vdm(7)).  The purpose of
       the Mirror Subdriver is to maintain redundant copies of distributed
       groups of disk blocks.

       A mirror has up to three children referred to as images.  In order to
       use an image of a mirror (that is, read from it or write to it), the
       image must be identical to the contents of the most up to date image
       on the mirror.

       When a mirror is first created, all of the images on the mirror are
       considered corrupt.  If only one image is provided at the time the
       mirror is created, it will not be corrupt.

       An image is no longer corrupt when it is synchronized with the most
       up to date image.  For the purpose of high availability, an image in
       the process of being synchronized is considered usable, but it only
       accepts writes and is not read from.  Doing this provides for the
       redundant storage of data on the mirror before the synchronization
       completes.  Although the image is no longer viewed as corrupt, it
       cannot be used as an up to date image for a synchronization because
       it is currently being synchronized.

       After an image has been synchronized, it may return to a corrupt
       state if a write fails to the image.  In this case, a message is
       displayed on the console indicating the write failure and the image
       on which it failed.

       If a mirror is written to, its images are marked slightly out of date
       from one another on disk.  This is done because any write to the
       mirror is not guaranteed to make it to all of the images of the
       mirror if the system experiences a failure.  By marking them slightly
       out of date to one another on disk, the recovery from the failure
       will initiate a synchronization of the images.  If a mirror is
       properly closed after being written, all of the images are marked
       identically and a synchronization will not be performed on a system
       reboot.

       Because the images of the mirror are usually on separate physical
       devices, all of the images of the mirror may not be available at the
       time the mirror is desired for use.  For example, one of the physical
       devices may be turned off or unusable because it has failed.  This
       produces a dilemma when attempting to determine the most up to date
       image because the failed drive may contain the most up to date image.



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




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


       For this reason, controls are made available as attributes of the
       mirror to choose whether the mirror should make synchronization
       decisions on reboot and whether it should make these decisions when
       images are missing from the mirror.

       Because missing and corrupt images introduce a decrease in the
       reliability of the mirror, controls are made available as attributes
       of the mirror to suppress usage of the mirror if a minimum number of
       images is not available for use.  Note that images that are currently
       being synchronized with the most up to date image are considered
       usable.

STRUCTURES
       The structures defined in this section are pointed to by fields in
       structures used by VDM commands (see vdm(7)).  The VDM command and
       the field in the argument structure will be described.  For many VDM
       commands, a subdriver ID is required as an input value.  The
       subdriver ID for the Mirror Subdriver is defined by
       DGVDMMIRRSUBDRIVERID.

       Unless otherwise noted, the version field in the following structures
       is an input field that must be set to
       DGVDMMIRRIOCTLPACKETVERSION0.  Additionally, all packets must
       have every byte set to zero before the are used.

   DGVDMCREATEINSTANCE
       The subdriverattributespacketptr field points to the following
       structure:

       struct dgvdmmirrcreatepacket
            {
            int                version;
            unsigned int       automaticsync       : 1;
            short              minimumimagesrequiredtouse;
            short              maximumimagesmissingtouse;
            unsigned int       millisecondsbetweensyncio;
            unsigned short     numberofimages;
            devt              imagedevicenumbers[DGVDMMIRRMAXIMAGES];
            };

       The numberofimages is an input field indicating the number of
       elements in the imagedevicenumbers array input field.  The
       imagedevicenumbers field contains the device numbers that are the
       initial images in the mirror.

       If only one image is supplied when the mirror is created, that image
       will be considered usable.  However, if more than one image is
       supplied, all of those images are considered corrupt.  To change this
       state, the mirror must be synchronized.  The image supplied as the
       source of the synchronization will become a usable image.  When the
       synchronization completes, the destination(s) of the synchronization
       will become usable.

       The automaticsync field is an input field.  If it is set to 1, then



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




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


       the mirror will automatically perform a synchronization when the
       system is rebooted and the images of the mirror are detected to be
       inconsistent.

       The minimumimagesrequiredtouse is a value that is compared
       against the number of non-corrupt images currently on the mirror
       (images that are the destination of a synchronization are not
       considered corrupt).  If the number of images currently on the mirror
       is less than minimumimagesrequiredtouse, then any attempts to
       open the mirror will fail and errno will be set to ENXIO.  If
       minimumimagesrequiredtouse is set to -1, then the test on open
       will not be applied.

       The maximumimagesmissingtouse is a value that is compared against
       the number of images that were on the mirror the last time it was
       used minus the number of images currently on the mirror (and an image
       was not explicitly removed from the mirror).  If the value is greater
       than the maximumimagesmissingtouse, then the mirror will fail to
       be opened and no automatic synchronizations will be started.  If
       maximumimagesmissingtouse is set to -1, then the test on open or
       when an automatic synchronization is being started will not be
       applied.

       The millisecondsbetweensyncio field is an input field indicating
       the number of time between I/O's when the mirror is automatically
       synchronized during system reboot. This field can be set even when
       the automaticsync field is not.

   DGVDMDELETEINSTANCE
       This command deletes the mirror.  Like all other instances, a mirror
       instance cannot be deleted if is open.  If the mirror is not open,
       but is synchronizing, then the synchronizations must be terminated
       before it is deleted.

   DGVDMLINKCHILDINSTANCE
       This command adds an image to a mirror instance, but since the role
       of a mirror image is not ambiguous, no subdriver specific packet is
       necessary for the childpacketptr field.

       An image added to a mirror is considered corrupt and not usable until
       it is synchronized with another image on the mirror.

   DGVDMUNLINKCHILDINSTANCE
       The use of this VDM command requires no subdriver specific packet.
       The use of this command will remove an image from the mirror.  The
       image to be removed from the mirror is contained in the VDM packet
       associated with this command.

       A mirror must have one child.  If the images being removed is the
       last child on the mirror, the request will fail and errno will be set
       to EINVAL.

       If a mirror is currently open, the last usable image of the mirror
       cannot be removed.  If all of the images are not usable and the



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




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


       mirror is open, any image can be removed.  If the mirror is not open,
       any image of the mirror can be removed.

       The minimum images required attribute of the mirror is not checked to
       determine if the image can be removed from the mirror.  This field
       only determines the usability of the mirror.  If the deletion of an
       image causes the number of images to fall below the minimum images
       required to use, the next time an attempt to open the mirror, the
       attempt will fail.

   DGVDMGETCHILDINSTANCE
       The childpacketptr points to the following structure:

       struct dgvdmmirrgetchildpacket
            {
            int                version;
            unsigned int   corrupt     : 1;
            unsigned int   syncsource : 1;
            unsigned int   syncdest   : 1;
            unsigned int   fractured   : 1;
            daddrt            syncblock;
            unsigned int       changegranularity;
            devt              sourceimage;
            };

       The corrupt field is set to 1 if the returned child is not currently
       synchronized with the other images on the mirror.  The syncsource
       field is set to 1 if this child is currently the source of a
       synchronization. The syncdest field is set to 1 if this child is
       currently the destination of a synchronization.  If the syncdest
       field is set, then the syncblock field is set to the current block
       in the mirror being synchronized with the source identified by the
       sourceimage field.

       If syncsource is set to 1, then this child is currently being used
       as the source of a synchronization.

       If fractured is set to 1, then the changegranularity field is set to
       contain the width of blocks to be monitored for change (see
       DGVDMMIRRFRACTUREIMAGE for a more detailed description).

   DGVDMGETATTRIBUTES
       The subdriverattributespacketptr field points to the following
       structure:

       struct dgvdmmirrgetpacket
            {
            int                version;
            unsigned int       automaticsync          : 1;
            unsigned int       syncinprogress        : 1;
            short              minimumimagesrequiredtouse;
            short              maximumimagesmissingtouse;
            unsigned int       millisecondsbetweensyncio;
            };



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




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


       Each of the above fields has the same meaning as in the create and
       synchronization packets described in this man page.

       The syncblock field identifies the current block being synchronized.
       This field can be used to determine how much of the synchronization
       has be completed.

   DGVDMUPDATEATTRIBUTES
       The subdriverattributespacketptr field points to the following
       structure:

       struct dgvdmmirrupdatepacket
            {
            int                version;
            unsigned int       automaticsync       : 1;
            short              minimumimagesrequiredtouse;
            short              maximumimagesmissingtouse;
            unsigned int       millisecondsbetweensyncio;
            };

       Each of the above fields has the same meaning as in the create packet
       described above.

IOCTLS
       The ioctls supported by the Mirror Subdriver are listed below.  The
       ioctl(2) command can be issued to the Mirror Subdriver in two ways:

       1.     Issue the command to an exported instance of the Mirror
              Subdriver.  In this case, the fd is an open file descriptor of
              the device node created when the instance was exported.  The
              command and the argument are described below.

       2.     Use the DGVDMIOCTLSUBDRIVER command described in more
              detail in vdm(7).  In this case, the fd is an open file
              descriptor of /dev/vdm device node.  The argument is a pointer
              to a structure that contains command and argument fields.  The
              values supplied for these fields are described below.

   DGVDMMIRRSYNCIMAGES
       This command starts a copy from a given source image to a given set
       of destination images.  The argument is a pointer to the following
       structure:

       struct dgvdmmirrsyncimagespacket
           {
           int                 version;
           unsigned int        millisecondsbetweensyncio;
           devt               sourceimage;
           unsigned short      numberofdestinations;
           devt               destimages[DGVDMMIRRMAXIMAGES - 1];
           };

       The sourceimage is an input field that is the device number of the
       image that will be used as the source of the synchronization.  The



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




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


       destimages input field is an array of device numbers of images that
       should be the destination of the synchronization.  The
       numberofdestinations is an input field containing the number of
       elements in the destimages array.  The millisecondsbetweensyncio
       field gives the time in milliseconds that the Mirror Subdriver should
       wait before doing the next I/O in the synchronization process.  A
       time of 0 indicates that the Mirror Subdriver will not wait between
       the I/O's.

       Only images that are not corrupt can be used as the source of the
       synchronization unless all of the images on the mirror are corrupt.
       In this case, any image can be identified as the source of the
       synchronization.  Only images that are corrupt can be given as
       destinations.

       Synchronizations can run simultaneously on a single mirror, but all
       simultaneous synchronizations must have the same source image.
       Giving multiple destination images in a single synchronization
       minimizes the use of system resources if more than one destination
       image is required to be synchronized.

       The fildes parameter to the ioctl(2) call (or the
       instancedevicenumber field of the DGVDMIOCTLSUBDRIVER VDM
       packet) identifies the mirror instance containing the images.

   DGVDMMIRRTERMINATESYNC
       This command terminates the copy to the given destination image.  The
       argument is a pointer to the following structure:

       struct dgvdmmirrterminatesyncpacket
           {
           int                 version;
           devt               destimage;
           };

       The destimage is an input field that identifies a destination of an
       ongoing synchronization.  The synchronization will terminate only on
       the given destination image.  All other synchronizations to other
       destinations will continue.  The given destination image will be left
       corrupt.

       The fildes parameter to the ioctl(2) call (or the
       instancedevicenumber field of the DGVDMIOCTLSUBDRIVER VDM
       packet) identifies the mirror instance containing the images.

   DGVDMMIRRTHROTTLESYNC
       This command changes the rate at which a synchronization is running.
       The argument is a pointer to the following structure:

       struct dgvdmmirrthrottlesyncpacket
           {
           int                 version;
           unsigned int        millisecondsbetweensyncio;
           devt               destimage;



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




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


           };

       The destimage is an input field that identifies a destination of an
       ongoing synchronization. The millisecondsbetweensyncio is the new
       time (in milliseconds) the the Mirror Subdriver will wait before it
       performs the next I/O on the synchronization.

       If more than one destination was provided when the synchronization
       was started, then this change in the speed of the synchronization
       will alter the speed of the I/O to all destinations specified when
       the synchronization was started.  Only one destination is required to
       find the on-going synchronization to change.

       The fildes parameter to the ioctl(2) call (or the
       instancedevicenumber field of the DGVDMIOCTLSUBDRIVER VDM
       packet) identifies the mirror instance containing the image.

   DGVDMMIRRFRACTUREIMAGE
       This command "fractures" an image on a mirror as opposed to
       "breaking" the image off of the mirror.  The result of this command
       is to terminate any I/O to the image, but allowing the image to
       remain on the mirror for the purpose of resynchronization. The
       argument is a pointer to the following structure:

       struct dgvdmmirrfractureimagepacket
           {
           int                 version;
           unsigned int        changegranularity;
           devt               imagedevicenumber;
           };

       The changegranularity is an input field that indicates the width (in
       blocks) that writes to the mirror should be monitored to reduce the
       number of blocks copied to perform a synchronization.

       For example, if the changegranularity was one, every block would
       would be monitored for change.  This would minimize the number of
       blocks copied during the synchronization may take up a large portion
       of memory to monitor the changes.  If the changegranularity was set
       to 16, then each group of 16 blocks on the mirror would be monitored
       - if one block in the 16 changed, then all of the 16 blocks would be
       copied when the image was synchronized.

       If the changegranularity is set to zero, then no monitoring of
       changes will be maintained.

       The imagedevicenumber is an input field that identifies the image
       to be fractured.  This image will be corrupt as a result of the
       fracture.

       If the image is unlinked from the mirror (see
       DGVDMUNLINKCHILDINSTANCE in the vdm(7) man page) then the
       monitoring of the changes will be terminated, requiring a full
       synchronization of the image if it is reintroduced to the mirror.



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




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


       If the system fails while an image is fractured from a mirror, all
       changes monitored will be lost, requiring a full synchronization of
       the image.

   DSKIOCGET
       This command returns the size of an instance and is described in more
       detail in dsk(7).  If the mirror is not usable by the standards
       described above, then this command will fail and errno will be set to
       EINVAL.

   DSKIOCUSAGE
       This command returns statistics associated with the use of an
       instance and is described in more detail in dsk(7).

   DSKIOCGETADDRESS
       This command returns the logical address at which a given memory
       address to the specified instance should be mapped.

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

       /*
        *  This example makes use of functions defined in the vdm(7) man page,
        *  the vdmpart(7) man page, and the vdmphys(7) man page. These functions
        *  defined in vdm(7) all begin with a vdm prefix, the functions
        *  defined in the vdmpart(7) man page begin with a vdmpart prefix, and
        *  the functions defined in the vdmphys(7) man page begin with a vdmphys
        *  prefix.
        */

       /***********************************************************************
        *  These macros initialize a packets used by the VDM and the Mirror
        *  Subdriver.
        ***********************************************************************/
       #define vdminitpacket(p) \
            (bzero((char *)&p, sizeof(p)), \
            p.version = DGVDMIOCTLPACKETVERSION0);

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

       /***********************************************************************
        *  This function sets the fields in a mirror create packet.
        ***********************************************************************/
       devt vdmmirrsetpacket (
       unsigned int  numberofimages,
       devt         images[],



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




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


       unsigned int  automaticsync,
       short         minimumimagesrequiredtouse,
       short         maximumimagesmissingtouse,
       struct dgvdmmirrcreatepacket * createpktptr
                                     )
       {
       devt                           devicenumber;
       int                             imageindex;

       vdmmirrinitpacket(*createpktptr);

       createpktptr->automaticsync = automaticsync;
       createpktptr->minimumimagesrequiredtouse =
                 minimumimagesrequiredtouse;
       createpktptr->maximumimagesmissingtouse =
                 maximumimagesmissingtouse;
       createpktptr->millisecondsbetweensyncio = 0;
       createpktptr->numberofimages = numberofimages;

       for (imageindex = 0; imageindex < numberofimages; imageindex++)
           {
           createpktptr->imagedevicenumbers[imageindex] = images[imageindex];
           }
       }

       /***********************************************************************
        *  This function creates a mirror instance for the given images.
        ***********************************************************************/
       devt vdmmirrcreateinstance (
       char *        instancename,
       unsigned int  numberofimages,
       devt         images[],
       unsigned int  automaticsync,
       short         minimumimagesrequiredtouse,
       short         maximumimagesmissingtouse
                                     )
       {
       struct dgvdmmirrcreatepacket createpkt;
       devt                           devicenumber;
       int                             imageindex;

       vdmmirrsetpacket (
            numberofimages,
            images,
            automaticsync,
            minimumimagesrequiredtouse,
            maximumimagesmissingtouse,
            &createpkt);
       devicenumber = vdmcreateinstance(
                          instancename, DGVDMMIRRSUBDRIVERID, &createpkt);

       return (devicenumber);
       }




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




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


       /***********************************************************************
        *  This function terminates the sync for a destination on a mirror.
        ***********************************************************************/
       int vdmmirrterminatesync (
       devt        mirror,
       devt        destimage
                                 )
       {
       struct dgvdmmirrterminatesyncpacket terminatepkt;
       int                                     status;

       vdmmirrinitpacket(terminatepkt);

       terminatepkt.destimage = destimage;

       status = vdmioctlsubdriver(
                          DGVDMMIRRSUBDRIVERID,
                    mirror,
                    DGVDMMIRRTERMINATESYNC,
                    (int)&terminatepkt);

       return (status);
       }

       /***********************************************************************
        *  This function copies the contents of one given image to given
        *  destination images.
        ***********************************************************************/
       int vdmmirrsyncimages (
       devt        mirror,
       devt        sourceimage,
       unsigned int numberofdestinations,
       devt        destinationimages[],
       timet       millisecondsbetweensyncio,
       int          wait
                               )
       {
       struct dgvdmmirrsyncimagespacket    syncpkt;
       struct dgvdmgetchildinstancepacket getchildpkt;
       struct dgvdmchildinstancepacket     childpkt;
       struct dgvdmmirrgetchildpacket      rolepkt;
       devt                                   devicenumber;
       int                                     imageindex;
       int                                     status;
       int                                     stillsyncing;

       vdmmirrinitpacket(syncpkt);

       syncpkt.sourceimage = sourceimage;
       syncpkt.millisecondsbetweensyncio = millisecondsbetweensyncio;
       syncpkt.numberofdestinations = numberofdestinations;

       for (imageindex = 0; imageindex < numberofdestinations; imageindex++)
           {



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




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


           syncpkt.destinationdevicenumbers[imageindex] =
            destinationimages[imageindex];
           }

       status = vdmioctlsubdriver(
                          DGVDMMIRRSUBDRIVERID,
                    mirror,
                    DGVDMMIRRSYNCIMAGES,
                    (int)&syncpkt);

       if (status != 0)
           {
           return (status);
           }

       if (wait)
           {
           vdminitpacket(getchildpkt);
           vdmmirrinitpacket(rolepkt);
           getchildpkt.parentsubdriverid = DGVDMMIRRSUBDRIVERID;
           getchildpkt.parentdevicenumber = mirror;
           getchildpkt.available = 1;
           getchildpkt.childinstancearrayptr = &childpkt;
           childpkt.childrolepacketptr = &rolepkt;
           for (;;)
            {
            /* Get the children and for the one that was the destination,
             * see if it is still syncing.
             */
               getchildpkt.key = 0;
            stillsyncing = 0;
            while ( (status = vdmioctl(DGVDMGETCHILDINSTANCE,
                               (int)&getchildpkt)) == 0)
                {
                for (imageindex = 0;
                  imageindex < numberofdestinations;
                  imageindex++)
                 {
                 if (childpkt.childinstance.specifiervalue.devicenumber ==
                     destinationimages[imageindex] &&
                     rolepkt.syncdest)
                     {
                     stillsyncing = 1;
                     }
                 }
                }
            if (!stillsyncing)
                {
                break;
                }
            sleep(10);
            }
           status = 0;
           }



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




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


       return (status);
       }

       /***********************************************************************
        *  This function identifies corrupt images and starts a synchronization
        *  on them.
        ***********************************************************************/
       int vdmmirrsyncmirror (
       devt        mirror,
       timet       millisecondsbetweensyncio
                             )
       {
       int                                status;
       int                                corruptimageindex;
       struct dgvdmgetchildinstancepacket
                              getchildpkt;
       struct dgvdmchildinstancepacket
                              childpkt;
       struct dgvdmmirrgetchildpacket imagepkt;
       devt                              goodimage;
       devt                              corruptimages[DGVDMMIRRMAXIMAGES - 1];
       devt                              imagedevicenumber;

       vdminitpacket(getchildpkt);
       vdmmirrinitpacket(imagepkt);

       childpkt.childrolepacketptr = &imagepkt;

       getchildpkt.key = 0;
       getchildpkt.parentdevicenumber = mirror;
       getchildpkt.parentsubdriverid = DGVDMMIRRSUBDRIVERID;
       getchildpkt.available = 1;
       getchildpkt.childinstancearrayptr = &childpkt;

       corruptimageindex = 0;
       goodimage = NODEV;
       while( (status = vdmioctl(DGVDMGETCHILDINSTANCE,
                         (int)&getchildpkt)) == 0)
           {
           if (childpkt.childinstance.devicenumberused)
            {
            imagedevicenumber =
                     childpkt.childinstance.specifiervalue.devicenumber;
            if (imagepkt.corrupt)
                {
                corruptimages[corruptimageindex] = imagedevicenumber;
                ++corruptimageindex;
                }
            else
                {
                goodimage = imagedevicenumber;
                }
            }
           }



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




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


       if (corruptimageindex > 0 && goodimage != NODEV)
           {
           status = vdmmirrsyncimages(
                        mirror,
                  goodimage,
                  corruptimageindex,
                  corruptimages,
                  millisecondsbetweensyncio,
                  0);
           }
       else
           {
           status = 0;
           }

       return (status);
       }

       int vdmmirrexample (void)
       {
       int   status;
       devt adevicenumber;
       devt bdevicenumber;
       devt cdevicenumber;
       devt images[2];

       /*
        *  Create two physical instances on which two partitions will be created
        *  to mirror.
        */
       adevicenumber = vdmphyscreateinstance("a", "sd(insc(),0)", ORDWR);
       if (adevicenumber == NODEV)
           {
           perror("sd(insc(),0)");
           exit(1);
           }

       bdevicenumber = vdmphyscreateinstance("b", "sd(insc(),1)", ORDWR);
       if (bdevicenumber == NODEV)
           {
           perror("sd(insc(),0)");
           exit(1);
           }

       /*
        *  Create two non-adjacent partitions to aggregate together.
        */
       images[0] = vdmpartcreateinstance(
                      "image0", 0, 10000, adevicenumber, NODEV);
       if (images[0] == NODEV)
           {
           perror("image 0");
           exit(1);
           }



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




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


       images[1] = vdmpartcreateinstance(
                      "image1", 0, 10000, bdevicenumber, NODEV);
       if (images[1] == NODEV)
           {
           perror("image 1");
           exit(1);
           }

       /*
        *  Create the mirror and sync it.
        */
       cdevicenumber = vdmmirrcreateinstance("c", 2, images, 1, 2, 0);
       if (cdevicenumber == NODEV)
           {
           perror("c");
           exit(1);
           }

       status = vdmmirrsyncmirror(cdevicenumber, 0);
       if (status != 0)
           {
           perror("sync c");
           exit(1);
           }

       exit(0);
       }


FILES
       Files in or under /dev

SEE ALSO
       vdm(7), vdmphys(7), vdmpart(7) ioctl(2).























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


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