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