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