Home > Veritas Storage Foundation™ Volume Manager Manual Pages
Each plex in the volume is a copy of the volume address space. The plex has subdisks associated with it. These subdisks provide backup storage for the volume address space.
It is possible to create a sparse plex, which is a plex without backup storage for some of the volume address space. The areas of a sparse plex that do not have a backing subdisk are called holes. An attempt to read a hole in a sparse plex fails. If there are other plexes that have backup storage for the read, then one of those plexes is read. Otherwise, the read fails. A write to a hole in a sparse plex is considered a success even though the data can't be read back.
In addition, a plex may be designated as a logging plex. This means that a log of blocks that are in transition will be kept, which enables fast recovery after a system failure. This feature is known as DRL, or dirty region logging. The log for each plex consists of a specially designated subdisk that is not part of the normal plex address space.
The ioctl commands supported by the volume virtual disk device interface are discussed later in this section. The format for calling each ioctl command is:
#include <sys/types.h> #include <sys/volclient.h> struct tag arg;int ioctl (int fd, int cmd, struct tag *arg);
The value of cmd is the ioctl command code and arg is usually a pointer to a structure containing the arguments that need to be passed to the kernel.
The return value for all these ioctls, with some exceptions, is zero if the command was successful, and -1 if it was rejected. If the return value is -1, then errno is set to indicate the cause of the error.
The following ioctl commands are supported:
long version; /*kernel version number*/ long max_volprivmem; /*max size of volprivmem area*/ major_t volbmajor; /*volume blk dev major number*/ major_t volcmajor; /*volume char dev major number*/ major_t plexmajor; /*plex device major number*/ long maxvol; /*max # of volumes supported*/ long maxplex; /*max # of associated plexes*/ long plexnum; /*max plexes per volume*/ long sdnum; /*max subdisks per plex*/ long max_ioctl; /*max size of ioctl data*/ long max_specio; /*max size of ioctl I/O op*/ long max_io; /*max size of I/O operation*/ long vol_maxkiocount; /*max # top level I/Os allowed*/ long dflt_iodelay; /*default I/O delay for utils*/ long max_parallelio; /*max # voldios allowed*/ long voldrl_min_regionsz; /*min DRL region size*/ long voldrl_max_drtregs; /*max # of DRL dirty regions*/ long vol_is_root; /*if set, root is volume*/ long mvrmaxround; /*max round-robin region size*/ long prom_version; /*PROM version of the system*/ long vol_maxstablebufsize; /*max size of copy buffer*/ size_t voliot_iobuf_limit; /*max total I/O trace buf spc*/ size_t voliot_iobuf_max; /*max size of I/O trace buffer*/ size_t voliot_iobuf_default; /*default I/O trace buf size*/ size_t voliot_errbuf_default; /*default error trace buf size*/ long voliot_max_open; /*max # of trace channels*/ size_t vol_checkpt_default; /*default checkpoint size*/ long volraid_rsrtransmax; /*max # of transient RSRs*/
The required I/O is identified to the command by the use of a vol_rdwr structure containing the following:
ulong_t vrw_flags; /*flags*/ voff_t vrw_off; /*offset in volume (sectors)*/ size_t vrw_size; /*number of sectors to Xfer*/ caddr_t vrw_addr; /*user address for Xfer*/
The vrw_flags field is currently unused; other fields are explained in the comments.
voff_t vi_offset; /*0x00 offset on plex*/ size_t vi_len; /*0x04 amount of data to read/write*/ caddr_t vi_buf; /*0x08 ptr to buffer*/ size_t vi_nsrcplex; /*0x0c number of source plexes*/ size_t vi_ndestplex; /*0x10 number of destination plexes*/ struct plx_ent *vi_plexptr; /*0x14 ptr to array of plex entries*/ ulong_t vi_flag; /*0x18 flags associated with op*/
The members of the plx_ent structure are:
char pe_name[NAME_SZ]; /*name of plex*/ int pe_errno; /*error number against plex*/
The vi_offset value specifies the sector offset of the I/O within the volume. It must be within the address range of the volume. Also, the entire range of the I/O from vi_offset to vi_offset \+ vi_len must be within the address range of the volume.
The vi_len field specifies the length of the I/O in sectors. It must be a between 0 and 120 sectors (VOL_MAXSPECIALIO).
The vi_buf field is a pointer to a buffer of vi_len sectors. The VERIFY_WRITE ioctl writes the data stored in this buffer.
The vi_nsrcplex field is the number of source plexes available for the operation and the vi_ndestplex field is the number of destination plexes available for the operation. The vi_nsrcplex and vi_ndestplex values must be between 0 and 8 (PLEX_NUM).
The vi_plexptr is a pointer to an array of plx_ent structures. The first vi_nsrcplex entries in the array are source plexes. The pe_name contains the name of the plex. If the name of the first source entry is the null string, then the kernel selects all plexes available for reading as part of the volume and fills in the pe_name fields.
After the source plexes, the next vi_ndestplex entries are the destination plexes. If the name of the first destination entry is the null string, then the kernel selects all plexes available for writing as part of the volume and fills in the pe_name fields.
After the I/O operations are performed, the plx_ent structures are copied back to the user. If the kernel selected the plexes, the names of the selected plexes are in the pe_name fields. The status of the operations on each plex are stored in the pe_errno field of the plx_ent structure for that plex.
The pe_errno field is 0 if the operation succeeded against the plex. If pe_errno isn't 0, then the error code indicates what happened to the plex. The possible values for pe_errno are:
The ioctls that do volume-special I/O are:
If the first source plex entry has a null string for the name, the kernel selects from any plex of the volume that is enabled for read access. The names of any selected plexes are copied into the appropriate plex entries.
If the first destination plex entry has a null string for the name, the kernel will write to all plexes of the volume that are enabled for write access. The names of selected plexes are copied into the appropriate plex entries.
When the list of source plexes has been compiled, the kernel tries to read each plex in order. A plex can't be read if it doesn't have backup storage covering the entire operation. Once a plex has been successfully read, all the destination plexes are written. The writes can succeed even if the destination plex is sparse and doesn't have backup storage to cover the entire write.
If the ioctl returns a value of -1, then some error has occurred which prevented the ATOMIC_COPY from working. If the return value is 0, then everything worked fine. If the return value is 1, then the pe_errno field must be examined to determine the errors on each individual plex. The status of the overall operation depends on these individual errors.
The vi_ndestplex field must be 0. If the vi_buf field is not NULL, then the data read from the plexes not marked with ESRCH is copied into the buffer specified by vi_buf.
As each plex is read, any data that has already been read is compared against the previous reads. If all the data for the plex passes, then any data that was read for the first time is copied into the comparison buffer. This allows VERIFY_READ operations to work if the volume contains sparse plexes. The data not represented by backup storage is not compared against anything.
The vi_nsrcplex field must be 0.
As each plex is read, any data that doesn't have backup storage on that plex is filled in from the write buffer. This allows VERIFY_WRITE operations to work if the volume contains sparse plexes. The data not represented by backup storage will always succeed.
This command returns -1 with errno set to EINVAL if the specified volume does not have logging enabled.
Last updated: 28 Jul 2003
Copyright ©2009 Symantec Corporation
All rights reserved.