vdmremap(7) DG/UX R4.11MU05 vdmremap(7)
NAME
vdmremap - Virtual Disk Manager Bad-Block Remapping Subdriver
DESCRIPTION
The Bad-Block Remapping Subdriver is used to prevent single-block
media failures from causing I/O failures to the applications. This
is done by intercepting I/O to the failed blocks and redirecting it
to a remap area with good blocks to store the data.
It is enabled at the partition level by linking the remap child for
the physical disk to the partition. If the remap child is not linked
to the partition, any media failures from the physical disk will
result in unrecoverable I/O errors being sent to the application.
Pictorially, a remap instance looks like this:
+-------------------+
| remap instance |
+-------------------+
| | |
+------------------+ | +----------------+
| | |
| | |
+-------------------+ +-------------------+ +-------------------+
| primary table | | remap area | | secondary table |
| partition | | partition | | partition |
| starts at 17 | | starts at 19 | | starts at 119 |
| is 2 blocks | | is 100 blocks | | is 2 blocks |
+-------------------+ +-------------------+ +-------------------+
| | |
| | |
+------------------+ | +----------------+
| | |
+-------------------+
| physical |
| sd(ncsc(0,7),0,0) |
+-------------------+
|
|
----------
( )
( )
( disk )
( drive )
( 1 )
( )
----------
Remap instances refer to their children by the roles that they play.
They always have three children: a primary bad-block table, a remap
area, and a redundant secondary bad-block table.
WHEN TO USE BAD-BLOCK REMAPPING
By default, when you format a physical disk with sysadm(1M), software
bad-block remapping will be enabled. Further, by default, when you
create a partition on a physical disk that has software bad-block
remapping enabled, the partition will also have it enabled. You can
override both defaults if you care to.
We recommend that you enable software bad-block remapping on all
disks and for all partitions as the default. In some situations,
however, you may safely choose to remove it.
One situation where software bad-block remapping can be safely
removed is if the disk is in a CLARiiON® RAID-5 stripe. In this
case, the RAID technology in the CLARiiON® is already protecting
against single bad blocks on the disks, so you can safely disable
software bad-block remapping for it. It can be enabled without
problems, but it would be redundant.
NVRAM (Non-Volatile Random Access Memory) boards also do not need to
have software bad-block remapping enabled for them, since they
provide single-bit ECC (Error Correcting Code) to prevent single-bit
errors from resulting in I/O failures. These NVRAM boards are
commonly used to hold Front-End Devices for VDM caches. See
vdmcache(1M) for more details.
MAPPING BAD BLOCKS
Without bad-block remapping enabled, a read or write to a bad block
on the disk (a hard error) will result in an error return for the
I/O. There is no way for an application to recover from this
situation, since there's no place else for it to write its data.
With bad-block remapping enabled, the data can be redirected to a
different known good block on the disk, and the I/O will succeed.
If a write fails with bad-block remapping enabled, the remap instance
will mark the failed block as bad in the primary and secondary remap
tables. The data for the failed block will be written into the next
available block in the remap area. The remaining good blocks in the
I/O are written to the original locations on the disk. Subsequent
reads to the remapped block will be intercepted by the remap instance
and the data will be read from the remap area block instead of the
original failed block.
This write remapping is transparent to the application, since the I/O
will succeed after the data blocks are safely on disk. An error
message will be sent to the operator's console to inform them of the
bad block on the disk.
If a read fails with bad-block remapping enabled, the situation is a
bit different. Since the original data was only written to the
original disk block which is now bad, the data is gone. It cannot be
reconstructed, so it is lost. A read to such a block requires the
remap instance to return an I/O error to the application because the
data is no longer available. Additionally, the block is entered into
the remap tables as "needing to be remapped". The next time a write
to the block is done, the remap instance will intercept it and
redirect the data to the next available block in the remap area.
Additionally, if you know beforehand that a given block on a disk is
bad, you can force the remap instance to cause it to be mapped before
it ever causes a failure. Sometimes disk manufacturers will ship a
list of known bad blocks with a disk. You should enter these bad
blocks into the bad-block table before loading the disk with your
data.
If a bad block resulted from some transient condition (like shaking
the disk drive), you can tell the remap instance to recover the
block. It will attempt to write and read the already remapped data
to the block. If the write and read are successful, the data will be
left in the repaired block and it will be removed from the bad-block
table.
Each physical disk that has bad-block remapping enabled has its own
remap instance. There can be only one remap instance per physical
disk. Always ensure that the remap child you are linking to a
partition is the remap instance for the disk the partition resides
on.
The remap instance maintains duplicate copies of the bad-block
information in the primary and secondary bad-block tables. If a bad
block inside one of the tables renders it unusable, the remap
instance will continue running using the other table. If a bad block
occurs in the remap area itself, the bad block will be mapped to
itself so that it is never used again, and the user data will be
mapped to a different remap area block.
Bad blocks on modern SCSI disks are rare due to their reliability.
In addition, most modern disks implement hardware bad-block remapping
that is done within the disk drive itself. This means that if any
bad blocks do occur, they will likely be handled by the disk drive,
and DG/UX software bad-block remapping will not be involved.
The primary and secondary remap tables must be formatted before they
can be used. The only way to format them is to install bad-block
remapping on a disk with admpdisk(1M).
BAD BLOCK REMAP STATES
These are the states a bad block can be in:
Unmapped The bad block has been noticed due to a read I/O failure
and has not yet been remapped. The next write to the
block will do the remapping.
Mapped The bad block has been fully remapped. Reads and writes
to the block are intercepted and redirected to the
remapped block in the remap area.
Forced The operator has forced the remap instance to list a
block as bad (perhaps because the disk manufacturer told
them it was bad). It is considered unmapped until the
next write is done to it, at which time it will be
converted to the mapped state.
Pseudo The block does not necessarily need remapping but its
contents are undetermined. It is treated as an unmapped
block.
Bad Remap The bad block occurred inside the bad-block remapping
area and it has been mapped to itself to prevent it from
being used anymore.
These states will be listed when you list bad blocks for a disk.
USABILITY
A remap instance is always usable, as long as the three partitions it
uses are usable. This is almost always the case, except when the
child partitions have been damaged in some way, which is rare.
EXPANDING AND SHRINKING REMAP INSTANCES
You cannot expand or shrink the remap instance itself (since it has
no size), nor the three child partitions it uses. The sizes are
determined when you initially create the remap instance and cannot be
changed later.
INSERTING AND EXTRACTING REMAP INSTANCES
Remap instances cannot be inserted or extracted. They can only be
created and deleted.
CLUSTER DISKS
All bad-block remapping functionality is available on cluster disks.
Bad blocks detected from one node will be atomically distributed to
the other nodes so that the remap instances on them will know about
the new bad block.
You may initially create cluster virtual disks with or without
remapping enabled, as your needs dictate.
However, you cannot change whether a virtual disk is using remapping
while it is clustered. To enable or disable remapping for a cluster
virtual disk, uncluster the disk, make the change, then put the disk
back into cluster mode.
ADMPDISK
The admpdisk(1M) command provides an easy-to-use interface for
listing and managing bad blocks. See the descriptions for the
list_mapped_blocks, verify, map_block, and unmap_block commands for
more details.
PROGRAMMING INTERFACE
The ioctl(2) system call is used for all communication with the Bad-
Block Remapping Subdriver. Use the open(2) system call to open a
channel to the /dev/vdm node, and issue all ioctl(2) commands through
that channel. See vdm(7) for more details on the programming
interface.
The <sys/ioctl.h> include file is required for communicating with the
Bad-Block Remapping Subdriver. The <errno.h>, <sys/dg_sysctl.h>,
<sys/types.h>, <stdio.h>, and <unistd.h> include files will be
helpful.
SUBDRIVER-SPECIFIC COMMANDS
DG_VDMREMAP_LIST_REMAP_TABLE
List the entries in the bad-block tables of a remap instance.
DG_VDMREMAP_FORCE_REMAP
Forcibly remap a block onto a spare block in the remap area.
DG_VDMREMAP_RECOVER_BAD_BLOCK
Attempt to recover a block that has been marked bad and already
remapped onto a block in the remap area.
COMMON DISK COMMANDS
Since the Remap Subdriver does not issue its I/O through its
children, it does not support either the DSKIOCGET or the DSKIOCUSAGE
command.
SUBDRIVER-SPECIFIC DEFINES
DG_VDMREMAP_SUBDRIVER_ID
The unique ID that identifies the Remap Subdriver.
DG_VDMREMAP_IOCTL_PACKET_VERSION_0
The version zero stamp used in all Remap Subdriver ioctl(2) packets.
The stamp indicates which version of the Remap Subdriver interface is
being used and allows the Remap Subdriver to support previous
versions without requiring that applications be recompiled.
DG_VDMREMAP_MAX_REMAP_TABLE_BLOCKS
The number of blocks in the bad-block table.
DG_VDMREMAP_TABLE_ENTRIES_PER_BLOCK
The number of entries in a block of the bad-block table.
DG_VDMREMAP_MAX_BLOCKS_REMAPPABLE
The maximum number of blocks that can be remapped per physical disk.
DG_VDMREMAP_PRIMARY_TABLE_CHILD
The value indicating that this child is the primary remap table. The
remap tables contain entries that record which blocks are remapped
and where in the remap area they are remapped to. The remap tables
are replicated.
DG_VDMREMAP_SECONDARY_TABLE_CHILD
The value indicating that this child is the secondary remap table.
The remap tables contain entries that record which blocks are
remapped and where in the remap area they are remapped to. The remap
tables are replicated.
DG_VDMREMAP_REMAP_AREA_CHILD
The value indicating that this child is the remap area. Bad blocks
are remapped to spare blocks within the remap area.
DG_VDMREMAP_UNMAPPED_BB_ENTRY
The status indicating that the listed bad block has not yet been
remapped.
DG_VDMREMAP_MAPPED_BB_ENTRY
The status indicating that the listed bad block has been remapped.
DG_VDMREMAP_FORCED_BB_ENTRY
The status indicating that the listed bad block has been forced to be
remapped.
DG_VDMREMAP_PSEUDO_BB_ENTRY
The status indicating that the listed bad block is a pseudo bad
block.
DG_VDMREMAP_BAD_REMAP_BB_ENTRY
The status indicating that the listed remap block has gone bad and
will not be used anymore.
STRUCTURES
dg_vdmremap_create_packet
The Remap Subdriver ioctl(2) packet for creating a new remap
instance. Put a pointer to this packet into the packet for the
DG_VDM_CREATE_INSTANCE command.
The three partitions must be properly initialized before creating the
remap instance to use them.
struct dg_vdmremap_create_packet
{
int version;
dev_t primary_remap_table;
dev_t secondary_remap_table;
dev_t remap_area;
};
version
The version of the packet.
primary_remap_table
The device number of the partition for the primary copy of the
bad-block table.
secondary_remap_table
The device number of the partition for the secondary copy of
the bad-block table.
remap_area
The device number of the partition for the remap area.
dg_vdmremap_get_child_packet
The Remap Subdriver ioctl(2) packet for getting child role
information about the children of a remap instance. Put a pointer to
this packet into the child instance sub-packet for the
DG_VDM_GET_CHILD_INSTANCE command.
struct dg_vdmremap_get_child_packet
{
int version;
int child_type;
};
version
The version of the packet.
child_type
The returned type of the child. The type will be
DG_VDMREMAP_PRIMARY_TABLE_CHILD,
DG_VDMREMAP_SECONDARY_TABLE_CHILD, or
DG_VDMREMAP_REMAP_AREA_CHILD. This identifies the role the
child plays for the remap instance.
dg_vdmremap_list_remap_table
The Remap Subdriver ioctl(2) packet for listing the entries in the
remap tables for a remap instance. Put a pointer to this packet into
the argument field of the packet for the DG_VDM_IOCTL_SUBDRIVER
command, and set the command field to DG_VDMREMAP_LIST_REMAP_TABLE.
Put the device number of the remap instance to query in the instance
device number field.
Each time the DG_VDMREMAP_LIST_REMAP_TABLE command is issued, the
information for the next bad-block entry will be returned. When
there are no more entries to return, error ENOENT will be returned.
Note that the information returned can become invalid if blocks are
remapped in between commands.
struct dg_vdmremap_list_remap_table
{
int version;
daddr_t bad_block;
daddr_t remap_index;
int status;
unsigned int key;
};
version
The version of the packet.
bad_block
The returned block number of the block that has been remapped.
Block numbers are zero-based.
remap_index
The returned block number in the remap area where the block
has been remapped to. Block numbers are zero-based.
status The returned status of the remap entry, indicating what the
state of the remapped block is. The status will be
DG_VDMREMAP_UNMAPPED_BB_ENTRY, DG_VDMREMAP_MAPPED_BB_ENTRY,
DG_VDMREMAP_FORCED_BB_ENTRY, DG_VDMREMAP_PSEUDO_BB_ENTRY, or
DG_VDMREMAP_BAD_REMAP_BB_ENTRY.
key The key for the request. Initialize the key to zero before
issuing the command for the first time. The key value will be
updated by the Remap Subdriver on each subsequent call to keep
track of its place in the list. Do not further alter the key
value, except to reset it to zero to start the listing over
again.
dg_vdmremap_force_remap
The Remap Subdriver ioctl(2) packet for forcing the remapping of a
block for a remap instance. Put a pointer to this packet into the
argument field of the packet for the DG_VDM_IOCTL_SUBDRIVER command,
and set the command field to DG_VDMREMAP_FORCE_REMAP. Put the device
number of the remap instance to update in the instance device number
field.
struct dg_vdmremap_force_remap
{
int version;
daddr_t block_number;
};
version
The version of the packet.
block_number
The block number of the block to be force remapped. Block
numbers are zero-based.
dg_vdmremap_recover_block
The Remap Subdriver ioctl(2) packet for attempting to recover a block
that has been remapped for a remap instance. Put a pointer to this
packet into the argument field of the packet for the
DG_VDM_IOCTL_SUBDRIVER command, and set the command field to
DG_VDMREMAP_RECOVER_BAD_BLOCK. Put the device number of the remap
instance to update in the instance device number field.
struct dg_vdmremap_recover_block
{
int version;
daddr_t block_number;
};
version
The version of the packet.
block_number
The block number of the block to attempt recovery on. Block
numbers are zero-based.
EXAMPLES
The following code fragments illustrate how to use the packets and
commands described in this man page. The fragments are not complete
and are not intended to be compilable or executable. In particular,
initialization code, instance locating code, and error handling are
left out for brevity.
Common includes and variables
#include <errno.h>
#include <sys/dg_sysctl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
int status; /* status from system call */
int vdm_channel; /* channel to /dev/vdm node */
Create a remap instance using already formatted children
dev_t remap_instance;
dev_t primary_instance;
dev_t area_instance;
dev_t secondary_instance;
struct dg_vdm_create_instance_packet create_pkt;
struct dg_vdmremap_create_packet remap_create_pkt;
create_pkt.version = DG_VDM_IOCTL_PACKET_VERSION_0;
create_pkt.subdriver_id = DG_VDMREMAP_SUBDRIVER_ID;
create_pkt.persistent = 1;
create_pkt.enable_disk_updates = 1;
strcpy (create_pkt.instance_name, ".Remap");
create_pkt.subdriver_attributes_packet_ptr = &remap_create_pkt;
remap_create_pkt.version = DG_VDMREMAP_IOCTL_PACKET_VERSION_0;
remap_create_pkt.primary_remap_table = primary_instance;
remap_create_pkt.secondary_remap_table = secondary_instance;
remap_create_pkt.remap_area = area_instance;
status = ioctl (vdm_channel,
DG_VDM_CREATE_INSTANCE,
&create_pkt);
remap_instance = create_pkt.device_number;
printf ("Remap device number = 0x%08x\n", remap_instance);
Link a remap child to a partition (enable remapping)
dev_t link_instance;
dev_t remap_instance;
struct dg_vdm_link_child_instance_packet link_pkt;
link_pkt.version = DG_VDM_IOCTL_PACKET_VERSION_0;
link_pkt.parent_device_number = link_instance;
link_pkt.parent_subdriver_id = DG_VDMPART_SUBDRIVER_ID;
link_pkt.child_device_number = remap_instance;
link_pkt.child_packet_ptr = NULL;
status = ioctl (vdm_channel,
DG_VDM_LINK_CHILD_INSTANCE,
&link_pkt);
Get the children of a remap instance
int i;
dev_t remap_instance;
dev_t child_instance;
struct dg_vdm_child_instance_packet child_pkt;
struct dg_vdm_get_child_instance_packet get_child_pkt;
struct dg_vdmremap_get_child_packet remap_get_child_pkt;
get_child_pkt.version = DG_VDM_IOCTL_PACKET_VERSION_0;
get_child_pkt.key = 0;
get_child_pkt.parent_device_number = remap_instance;
get_child_pkt.parent_subdriver_id = DG_VDMREMAP_SUBDRIVER_ID;
get_child_pkt.available = 0;
get_child_pkt.child_instance_array_ptr = NULL;
status = ioctl (vdm_channel,
DG_VDM_GET_CHILD_INSTANCE,
&get_child_pkt);
printf ("Number of children = %d\n",
get_child_pkt.number_of_children);
get_child_pkt.key = 0;
get_child_pkt.available = 1;
get_child_pkt.child_instance_array_ptr = &child_pkt;
child_pkt.child_role_packet_ptr = &remap_get_child_pkt;
remap_get_child_pkt.version = DG_VDMREMAP_IOCTL_PACKET_VERSION_0;
i = 0;
while (1)
{
status = ioctl (vdm_channel,
DG_VDM_GET_CHILD_INSTANCE,
&get_child_pkt);
if ((status == -1) && (errno == ENOENT))
{
break;
}
printf ("Child %d\n", i);
switch (remap_get_child_pkt.child_type)
{
case DG_VDMREMAP_PRIMARY_TABLE_CHILD:
printf ("Primary table\n");
break;
case DG_VDMREMAP_SECONDARY_TABLE_CHILD:
printf ("Secondary table\n");
break;
case DG_VDMREMAP_REMAP_AREA_CHILD:
printf ("Remap area\n");
break;
}
if (child_pkt.child_instance.device_number_used)
{
child_instance = child_instance_pkt.child_instance.
specifier_value.device_number;
printf ("Child device number = 0x%08x\n", child_instance);
if (child_pkt.child_subdriver_id ==
DG_VDM_SUBDRIVER_ID_OF_A_NON_VDM_DEVICE)
{
printf (" Non-vdm child\n");
}
else
{
printf (" Child subdriver 0x%08x\n",
child_pkt.child_subdriver_id);
}
}
else
{
printf (" Missing child ID %08x,%08x\n",
child_pkt.child_instance.specifier_value.id.generation,
child_pkt.child_instance.specifier_value.id.system_id);
}
printf ("\n");
i++;
}
Unlink a remap child from a partition (disable remapping)
dev_t unlink_instance;
dev_t remap_instance;
struct dg_vdm_unlink_child_instance_packet unlink_pkt;
unlink_pkt.version = DG_VDM_IOCTL_PACKET_VERSION_0;
unlink_pkt.parent_device_number = unlink_instance;
unlink_pkt.child_instance.device_number_used = 1;
unlink_pkt.child_instance.specifier_value.device_number =
remap_instance;
status = ioctl (vdm_channel,
DG_VDM_UNLINK_CHILD_INSTANCE,
&unlink_pkt);
List the bad blocks for a remap instance
int blocks_listed;
char * status_text_ptr;
dev_t remap_instance;
struct dg_vdm_ioctl_subdriver_packet ioctl_pkt;
struct dg_vdmremap_list_remap_table list_remap_pkt;
ioctl_pkt.version = DG_VDM_IOCTL_PACKET_VERSION_0;
ioctl_pkt.subdriver_id = DG_VDMREMAP_SUBDRIVER_ID;
ioctl_pkt.instance_device_number = remap_instance;
ioctl_pkt.command = DG_VDMREMAP_LIST_REMAP_TABLE;
ioctl_pkt.argument = (int) &list_remap_pkt;
list_remap_pkt.version = DG_VDMREMAP_IOCTL_PACKET_VERSION_0;
list_remap_pkt.key = 0;
printf ("\n");
printf (" Bad block Remapped to Status\n");
printf ("---------- ----------- --------\n");
while (1)
{
status = ioctl (vdm_channel,
DG_VDM_IOCTL_SUBDRIVER,
&ioctl_pkt);
if ((status == -1) && (errno == ENOENT))
{
break;
}
switch (list_remap_pkt.status)
{
case DG_VDMREMAP_UNMAPPED_BB_ENTRY:
status_text_ptr = "Unmapped";
break;
case DG_VDMREMAP_MAPPED_BB_ENTRY:
status_text_ptr = "Mapped";
break;
case DG_VDMREMAP_FORCED_BB_ENTRY:
status_text_ptr = "Forced";
break;
case DG_VDMREMAP_PSEUDO_BB_ENTRY:
status_text_ptr = "Pseudo";
break;
case DG_VDMREMAP_BAD_REMAP_BB_ENTRY:
status_text_ptr = "Bad remap";
break;
}
printf ("%10ld %10ld %s (%d)\n",
list_remap_pkt.bad_block,
list_remap_pkt.remap_index,
status_text_ptr,
list_remap_pkt.status);
blocks_listed++;
}
printf ("\nNumber of blocks listed = %d\n", blocks_listed);
Force a bad block to be remapped
dev_t remap_instance;
daddr_t bad_block;
struct dg_vdm_ioctl_subdriver_packet ioctl_pkt;
struct dg_vdmremap_force_remap force_remap_pkt;
ioctl_pkt.version = DG_VDM_IOCTL_PACKET_VERSION_0;
ioctl_pkt.subdriver_id = DG_VDMREMAP_SUBDRIVER_ID;
ioctl_pkt.instance_device_number = ioctl_instance;
ioctl_pkt.command = DG_VDMREMAP_FORCE_REMAP;
ioctl_pkt.argument = (int) &force_remap_pkt;
force_remap_pkt.version = DG_VDMREMAP_IOCTL_PACKET_VERSION_0;
force_remap_pkt.block_number = bad_block;
status = ioctl (vdm_channel,
DG_VDM_IOCTL_SUBDRIVER,
&ioctl_pkt);
Recover a bad block
dev_t remap_instance;
daddr_t bad_block;
struct dg_vdm_ioctl_subdriver_packet ioctl_pkt;
struct dg_vdmremap_recover_block recover_remap_pkt;
ioctl_pkt.version = DG_VDM_IOCTL_PACKET_VERSION_0;
ioctl_pkt.subdriver_id = DG_VDMREMAP_SUBDRIVER_ID;
ioctl_pkt.instance_device_number = ioctl_instance;
ioctl_pkt.command = DG_VDMREMAP_RECOVER_BAD_BLOCK;
ioctl_pkt.argument = (int) &recover_remap_pkt;
recover_remap_pkt.version = DG_VDMREMAP_IOCTL_PACKET_VERSION_0;
recover_remap_pkt.block_number = bad_block;
status = ioctl (vdm_channel,
DG_VDM_IOCTL_SUBDRIVER,
&ioctl_pkt);
FILES
/dev/dsk
Directory for the block special device nodes for virtual
disks. These are the buffered access device nodes.
/dev/rdsk
Directory for the character special device nodes for virtual
disks. These are the unbuffered (or raw) access device nodes.
/dev/vdm
Device node for issuing all ioctl(2) commands.
/usr/include/sys/ioctl.h
ioctl(2) definitions.
ACCESS CONTROL
Access control for the standard VDM framework commands is controlled
by the VDM itself. See the vdm(7) man page for a listing of these
controls.
Access control for the Bad-Block Remapping Subdriver commands is
controlled by the subdriver itself.
All users may execute this command: DG_VDM_GET_CHILD_INSTANCE,
DG_VDMREMAP_LIST_REMAP_TABLE.
Only users with appropriate privilege may execute these commands:
DG_VDM_CREATE_INSTANCE, DG_VDMREMAP_FORCE_REMAP,
DG_VDMREMAP_RECOVER_BAD_BLOCK.
On a generic DG/UX system, appropriate privilege is granted by having
an effective UID of 0 (root). See the appropriate_privilege(5) man
page for more information.
On a system with DG/UX information security, appropriate privilege is
granted by having one or more specific capabilities enabled in the
effective capability set of the user. See the cap_defaults(5) man
page for the default capabilities for these commands.
RETURN VALUE
The return value from the ioctl(2) system call used to issue the
command will be one of the following:
0 The command was successful.
-1 An error occurred. errno is set to indicate the error.
DIAGNOSTICS
There are descriptive extended error message strings available for
most of the error codes. They can be retrieved with the
dg_ext_errno(2), extended_strerror(3C), and extended_perror(3C)
routines.
Errno may be set to one of the DG/UX standard error codes. See
/usr/include/sys/errno.h for a listing of those error codes.
Errno may be set to one of the standard error codes provided by the
VDM framework. See vdm(7) for a listing of those error codes.
Errno may also be set to one of the following error codes that are
specific to this subdriver:
EBUSY The remap virtual disk is already enabled for I/O.
EINVAL The sizes of the replicated remap tables and the remap area do
not match.
EINVAL The block cannot be remapped because it is in a partition that
is not remapped or it is outside the boundaries of the disk.
EINVAL An entry for the block already exists in the remap table.
EIO A bad block was found in the remap tables on disk.
ENOENT The remap entry for the remap block could not be found.
ENOENT There are no more remap blocks to list.
ENOSPC There are no free remap blocks left in the remap area.
SEE ALSO
ioctl(2), dsk(7), rdsk(7), vdm(7).
Licensed material--property of copyright holder(s)