/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/nsc_thread.h>
#include <sys/sysmacros.h>
#include "dsw.h"
#include "dsw_dev.h"
#include "../rdc/rdc_update.h"
#ifdef DS_DDICT
#include "../contract.h"
#endif
/*
* Instant Image
*
* This file contains the core implementation of II.
*
* II is implemented as a simple filter module that pushes itself between
* user (SV, STE, etc.) and SDBC or NET.
*
*/
sizeof (d) - (uintptr_t)&((t *)0)->m)
extern dev_info_t *ii_dip;
&ip->bi_cluster)
/* of area cleared in volume when a dependent */
/* shadow is disabled. */
/* max # of chunks in copy loop before delay */
/* length of delay during update loop */
static int _ii_shutting_down = 0;
static int _ii_concopy_init = 0;
static int _ii_instance = 0;
void _ii_deinit_dev();
static _ii_info_t *_ii_find_vol(char *, int);
extern int ii_tinit(_ii_info_t *);
extern void ii_reclaim_overflow(_ii_info_t *);
static int ii_overflow_attach(_ii_info_t *, char *, int);
char **);
extern const int dsw_major_rev;
extern const int dsw_minor_rev;
extern const int dsw_micro_rev;
extern const int dsw_baseline_rev;
/*
* These constants are used by ii_overflow_free() to indicate how the
* reclamation should take place.
* NO_RECLAIM: just detach the overflow from the set; do not
* attempt to reclaim chunks, do not decrement the
* used-by count
* RECLAIM: reclaim all chunks before decrementing the used-by count
* INIT_OVR: decrement the used-by count only; do not reclaim chunks
*/
#define NO_RECLAIM 0
int flag;
int rtype;
int wait;
int rc;
};
/* set-specific kstats info */
};
/*
* _ii_init_dev
* Initialise the shadow driver
*
*/
int
{
if (_ii_local_mem == NULL)
return (ENOMEM);
}
return (ENOMEM);
}
return (0);
}
/*
* _ii_deinit_dev
* De-initialise the shadow driver
*
*/
void
{
if (_ii_io)
(void) nsc_unregister_io(_ii_io, 0);
if (_ii_ior)
(void) nsc_unregister_io(_ii_ior, 0);
if (_ii_local_mem)
(void) nsc_unregister_mem(_ii_local_mem);
if (ii_volume_update)
(void) nsc_unregister_svc(ii_volume_update);
if (ii_report_luns)
(void) nsc_unregister_svc(ii_report_luns);
if (ii_get_initiators)
(void) nsc_unregister_svc(ii_get_initiators);
if (_ii_concopy_init)
_ii_concopy_init = 0;
}
static char *
{
char *rc;
return ("");
else
return (rc);
}
/*
* _ii_rlse_d
* Internal mechanics of _ii_rlse_devs(). Takes care of
* resetting the ownership information as required.
*/
static void
_ii_info_t *ip;
{
_ii_info_dev_t *, rip,
_ii_info_dev_t *, cip);
if (raw) {
} else {
}
} else {
}
}
} else {
if (raw) {
} else {
}
} else {
}
}
}
}
/*
* _ii_rlse_devs
* Release named underlying devices.
*
* NOTE: the 'devs' argument must be the same as that passed to
* the preceding _ii_rsrv_devs call.
*/
void
_ii_info_t *ip;
int devs;
{
if (!ip) {
return;
}
else
}
}
if (--(ip->bi_bmprsrv) == 0)
}
}
/*
* _ii_rsrv_d
* Reserve device flagged, unless its companion is already reserved,
* in that case increase the reserve on the companion.
*/
static int
_ii_info_t *ip)
{
_ii_info_dev_t *p = NULL;
int other = 0;
int rc;
/*
* If user wants to do a cache reserve and it's already
* raw reserved, we need to do a real nsc_reserve, so wait
* until the release has been done.
*/
ip->bi_release++;
}
ip->bi_release--;
}
p = rid;
if (!raw) {
other = 1;
}
p = cid;
if (raw) {
other = 1;
}
}
if (p) {
if (other) {
p->bi_orsrv++;
} else {
p->bi_rsrv++;
}
if (p->bi_iodev) {
}
return (0);
}
if (p->bi_iodev) {
}
p->bi_rsrv++;
if (raw)
}
return (rc);
}
/*
* _ii_rsrv_devs
* Reserve named underlying devices.
*
*/
int
{
int rc = 0;
int got = 0;
if (!ip) {
return (EINVAL);
}
flag)) != 0) {
"!ii: nsc_reserve multi-master failed");
} else {
}
} else {
"!ii: nsc_reserve master failed %d", rc);
} else {
}
}
}
"!ii: nsc_reserve shadow failed %d", rc);
} else {
}
}
if ((ip->bi_bmprsrv == 0) &&
"!ii: nsc_reserve bitmap failed %d", rc);
} else {
(ip->bi_bmprsrv)++;
}
}
return (rc);
}
static int
{
int rc;
++ip->bi_rsrvcnt;
}
return (rc);
}
static int
{
int nosig;
nosig = 1;
while (ip->bi_rsrvcnt > 0) {
if (!nosig) {
break;
}
}
}
static void
{
if (ip->bi_rsrvcnt <= 0) {
return;
}
--ip->bi_rsrvcnt;
}
static int
{
int rc;
return (rc);
/*
* make certain that the last bits of the last byte of the bitmap
* aren't filled as they may be copied out to the user.
*/
++chunk_num;
if ((max_chunk & 0x7) != 0)
}
return (0);
}
static int
{
int size;
unsigned char *bmp;
ip->bi_keyname;
return (1);
}
if (all) {
while (size-- > 0)
*bmp++ = (unsigned char)0xff;
} else {
/* failed to read bitmap */
}
}
/* check that no user of volume objects */
}
}
static int
{
}
/*
* ii_volume: check if vol is already known to Instant Image and return
* volume type if it is.
*/
static int
{
/* scan overflow volume list */
break;
}
if (op) {
return (OVR);
}
if (!locked) {
}
break;
}
break;
}
break;
}
}
if (!locked) {
}
return (rc);
}
/*
* ii_open_shadow: open shadow volume for both cached and raw access,
* if the normal device open fails attempt a file open to allow
* shadowing into a file.
*/
static int
{
int rc = 0;
int file_rc = 0;
file_rc = 1;
return (rc);
}
}
else
if (file_rc == 0) {
} else {
}
return (rc);
}
return (0);
}
static void
{
}
static void
{
}
static int
{
int rc;
int sibling;
int exported;
rc = 1;
rc = 0;
rc = 0;
return (rc);
}
#ifndef DISABLE_KSTATS
/*
* _ii_kstat_create
* Create and install kstat_io data
*
* Returns 0 if kstats couldn't be created, otherwise it returns
* a pointer to the created kstat_t.
*/
static kstat_t *
{
int setnum;
char *nptr;
static int mstnum = 0;
switch (*type) {
case 'm':
break;
case 's':
/* assumption: shadow kstats created before bitmap */
break;
case 'b':
break;
default:
setnum = -1;
break;
}
/*
* The name of the kstat, defined below, is designed to work
* with the 'iostat -x' command. This command leaves only
* 9 characters for the name, and the kstats built in to Solaris
* all seem to be of the form <service><number>. For that
* reason, we have chosen ii<type><number>, where <type> is
* m, s, b, or o (for master, shadow, bitmap, and overflow
* respectively), and the number is monotonically increasing from
* 0 for each time one of those <type>s are created. Note that
* the shadow and bitmap are always created in pairs and so, for
* any given set, they will have the same <number>.
*/
if (result) {
} else {
ip->bi_keyname);
}
return (result);
}
/*
* _ii_overflow_kstat_create
* Create and install kstat_io data for an overflow volume
*
* Returns 0 if kstats couldn't be created, otherwise it returns
* a pointer to the created kstat_t.
*
* See comments in _ii_kstat_create for additional information.
*
*/
static kstat_t *
{
char *nptr;
static int ovrnum = 0;
if ((result =
} else {
}
return (result);
}
#endif
static void
{
static int whinged = 0;
int num_parts;
int leftover;
/*
* NOTE: the following lines must be changed if DSW_NAMELEN
* ever changes. You'll need a part[] for every kscharsize
* characters (or fraction thereof). The ii_kstat_set_t
* definition in dsw_dev.h will also need new ovr_? entries.
*/
if (str) {
}
if (leftover) {
++num_parts;
}
/*
* DSW_NAMELEN is 64 and kscharsize is 15.
* It's always "whinged"
*/
if (!whinged) {
#ifdef DEBUG
"to store volume name in kstats");
#endif
whinged = 1;
}
}
offset = 0;
for (i = 0; i < num_parts; i++) {
}
}
static int
{
if (KSTAT_WRITE == rw) {
return (EACCES);
}
/* copy values over */
/* update bitmap counters if necessary */
ip->bi_copybits = 0;
&ip->bi_copybits,
}
}
ip->bi_shdbits = 0;
&ip->bi_shdbits,
}
}
/* copy volume names */
if (ip->bi_overflow) {
} else {
}
} else {
}
/* make sure value.c are always null terminated */
return (0);
}
/*
* _ii_config
* Configure an II device pair
*
* Returns 0 if the pairing was configured, otherwise an
* error code. The ioctl data stucture is copied out to the user
* and contains any additional error information, and the master
* and shadow volume names if not supplied by the user.
*
* Description:
* Reads the user configuration structure and attempts
* to establish an II pairing. The snapshot of the master
* device is established at this point in time.
*/
int
{
int rc;
int type;
int nshadows;
int add_to_mst_top;
int import;
int existing;
int resized;
int rtype;
/* Import is a once only operation like an enable */
*rvp = 0;
if (ilp32) {
return (ENOMEM);
}
return (EFAULT);
return (EFAULT);
kstatus = spcs_s_kcreate();
return (ENOMEM);
if (_ii_shutting_down)
if (uconf.bitmap_vol[0] == 0)
if (!ip) {
}
}
/* First check the list to see if uconf.bitmap_vol's already there */
}
}
if (import) {
}
if (existing) {
/*
* ii_config is used by enable, import and resume (existing)
* If not importing or resuming, then this must be enable.
* Indicate this fact for SNMP use.
*/
/*
* Couldn't read bitmap, mark master and shadow as
* unusable.
*/
DSW_SHDOFFLINE, ip);
/*
* Set cluster tag for this element so it can
* be suspended later
*/
/* need to check on master, might be shared */
goto header_checked;
}
/* check the header */
/* get first block of bit map */
if (ii_debug > 0)
"!ii: _ii_bm_header_get returned NULL");
DSW_EHDRBMP));
}
}
/* Restore copy throttle parameters, if header version is 3 */
}
/* Restore cluster & group names, if header version is 4 */
/* cluster */
if (*bm_header->clstr_name) {
}
/* group */
if (*bm_header->group_name) {
}
}
/* restore latest modification time, if header version >= 5 */
}
/* Fetch master and shadow names from bitmap header */
if (uconf.master_vol[0] == 0)
if (uconf.shadow_vol[0] == 0)
/* return the fetched names to the user */
if (ilp32) {
KM_SLEEP);
return (ENOMEM);
}
} else {
}
if (rc) {
return (EFAULT);
}
}
if (ii_debug > 0)
"!II: Resuming short shadow volume");
if (bm_header->overflow_vol[0] != 0)
bm_header->overflow_vol, 0)) != 0) {
return (spcs_s_ocopyoutf(&kstatus,
}
}
}
}
/* check that no volume has been given twice */
}
}
}
/* check that master is not already a bitmap, shadow or overflow */
}
/* check that shadow is not used as anything else */
}
/* Setup the table bitmap operations table */
switch (ii_bitmap) {
case II_KMEM:
if (ii_debug > 0)
break;
case II_FWC:
hints = 0;
(void) nsc_node_hints(&hints);
if ((hints & NSC_FORCED_WRTHRU) == 0)
else
if (ii_debug > 0) {
"volatile" : "persistent");
}
break;
case II_WTHRU:
default:
if (ii_debug > 0)
break;
}
/*
* If we found aother shadow volume with the same name,
* If this is an resume operation,
* If this shadow is in the exported state
* then try an on the fly join instead
*/
break;
/*
* Stop any copy in progress
*/
;
/*
* Start the imported shadow teardown
*/
/* disable accesss to imported shadow */
/* Wait for any I/O's to complete */
}
/* this rw_enter forces us to drain all active IO */
/* remove ip from _ii_info_top linked list */
break;
}
}
}
/* Gain access to both bitmap volumes */
}
/* Merge imported bitmap */
/* Release access to bitmap volume */
/* Clear the fact that we are exported */
/* Release resources */
}
/*
* Handle non-exported shadow
*/
DSW_EOPEN));
}
}
/*
* allocate _ii_concopy_sema and set to a value that won't allow
* all cache to be allocated by copy loops.
*/
if (asize > 0) {
if (!II_SUCCESS(rc))
}
if (ii_nconcopy < 2)
ii_nconcopy = 2;
ASSERT(ii_nconcopy > 0);
SEMA_DRIVER, NULL);
_ii_concopy_init = 1;
}
/* check for shared master volume */
break;
if (!hip)
break;
/* Check if master is offline */
if (hip) {
DSW_EOFFLINE));
}
}
DSW_EOPEN));
}
DSW_EOPEN));
}
}
_ii_info_top = ip;
if (nshadows) {
/* link new shadow group together with others sharing master */
if (ii_debug > 0)
"!II: shadow %s shares master %s with other shadow"
if (add_to_mst_top) {
_ii_mst_top = hip;
}
}
} else {
keyoffset = 0;
}
sizeof (ii_kstat_set) / sizeof (kstat_named_t),
} else {
}
#ifndef DISABLE_KSTATS
/* create kstats information */
} else {
}
#endif
(void) _ii_reserve_begin(ip);
rc = DSW_ERSRVFAIL;
goto fail;
}
rc = 0; /* no master for imported volumes */
mst_size = 0;
} else
if (rc == 0)
else
(mst_size < 1)) ||
(shd_size < 1)) ||
/* could be really zero, or could be > 1 TB; fail the enable */
}
if (rc != 0) { /* rc set means an nsc_partsize() failed */
/*
* If existing group, mark bitmap as offline and set
* bmp_size to "right size".
*/
if (existing) {
goto no_more_bmp_tests;
}
rc = DSW_EPARTSIZE;
goto fail;
}
/*
* Check with RDC if the master & shadow sizes are different.
* Once II is enabled, the shadow size will be made to appear
* the same as the master, and this will panic RDC if we're
* changing sizes on it.
*/
"size on RDC");
rc = DSW_EOPACKAGE;
goto fail;
}
/* bitmap volume too small */
if (ii_debug > 0)
rc = DSW_EBMPSIZE;
goto fail;
}
/* shadow volume too small */
if (ii_debug > 0)
rc = DSW_ESHDSIZE;
goto fail;
}
KM_SLEEP);
goto fail;
}
if (existing == 0) {
/* first time this shadow has been set up */
if (ii_debug > 0)
"!ii: _ii_bm_header_get returned NULL");
rc = DSW_EHDRBMP;
goto fail;
}
/* copy pathnames into it */
if (uconf.cluster_tag[0] != 0)
if (uconf.group_name[0] != 0)
if (import) {
}
if (resized) {
}
/* write it to disk */
if (!II_SUCCESS(rc)) {
rc = DSW_EHDRBMP;
goto fail;
}
/*
* shadow volume smaller than master, must use a dependent
* copy with a bitmap file stored mapping for chunk locations.
*/
/* number of chunks in shadow volume */
if (ii_debug > 1)
/* do not add in partial chunk at end */
ip->bi_mstchks++;
if (ii_debug > -1) {
}
rc = DSW_EHDRBMP;
goto fail;
}
/* following values are written to header by ii_tinit */
#if (defined(NSC_MULTI_TERABYTE) && !defined(II_MULTIMULTI_TERABYTE))
#endif
ip->bi_mstchks++;
#ifdef II_MULTIMULTI_TERABYTE
#else
/* still have 31 bit chunkid's */
#endif
ip->bi_shdchkused = 0;
} else {
ip->bi_shdchkused = 0;
}
if (rc == 0)
if (rc == 0)
if (rc == 0)
if (rc) {
rc = DSW_EHDRBMP;
goto fail;
}
/* check that changing shadow won't upset RDC */
rc = DSW_EOPACKAGE;
goto fail;
}
/* no _ii_reserve_end() here - we must register first */
if (!nshadows)
if (!ii_register_ok(ip)) {
rc = DSW_EREGISTER;
goto fail;
}
/* no _ii_reserve_begin() here -- we're still in process */
if (ii_debug > 0)
rc = 0;
}
}
if (rc == 0)
if (existing) {
goto no_more_bmp_tests;
}
rc = DSW_EHDRBMP;
goto fail;
}
/*
* If the header is dirty and it wasn't kept on persistent storage
* then the bitmaps must be assumed to be bad.
*/
if (type == DSW_GOLDEN_TYPE) {
else {
/* No copying, so they're just different */
if (rc) {
rc = DSW_EHDRBMP;
goto fail;
}
}
} else
rc = DSW_EHDRBMP;
goto fail;
}
}
if (!II_SUCCESS(rc)) {
rc = DSW_EHDRBMP;
goto fail;
}
if (!nshadows)
if (!ii_register_ok(ip)) {
rc = DSW_EREGISTER;
goto fail;
}
if (ii_debug > 0)
rc = 0;
/* Copy was in progress, so continue it */
}
fail:
/* remove ip from _ii_info_top linked list */
break;
}
}
}
static int
{
int rc;
int rtype;
return (DSW_ENOTFOUND);
}
/*
* Cannot disable an independent copy while still copying
* as it means that a data dependency exists.
*/
return (DSW_EDEPENDENCY);
}
/* Cannot disable a dependent shadow while RDC is unsure */
return (DSW_EOPACKAGE);
}
ii_need_same_size(ip)) {
/* We can't disable the set whilst RDC is using it */
"volume size on RDC");
return (DSW_EOPACKAGE);
}
}
return (DSW_ERSRVFAIL);
}
if ((ii_header < 128) &&
/*
* Not a full copy so attempt to prevent use of partial copy
* by clearing where the first ufs super-block would be
* located. Solaris often incorporates the disk header into
* the start of the first slice, so avoid clearing the very
* first 16 blocks of the volume.
*/
if (ii_debug > 1)
NSC_RDWRBUF, &tmp);
if (II_SUCCESS(rc)) {
if (II_SUCCESS(rc)) {
(128 - ii_header), 0);
}
}
if (tmp)
(void) nsc_free_buf(tmp);
if (!II_SUCCESS(rc))
}
/* this rw_enter forces us to drain all active IO */
/* remove ip from _ii_info_top linked list */
break;
}
}
}
if (rc == 0)
if (ii_debug > 1)
/* write it to disk */
}
}
op->ii_urefcnt--;
}
if (op->ii_urefcnt == 0) {
}
}
return (0);
}
/*
* _ii_disable
* Deconfigures an II pair
*
* Returns 0 if the pair was disabled. Otherwise an error code
* is returned and any additional error information is copied
* out to the user.
*
* Description:
* Reads the user configuration structure and attempts to
* deconfigure that pairing based on the master device pathname.
*/
int
{
int reclaim;
*rvp = 0;
if (ilp32) {
return (EFAULT);
return (EFAULT);
kstatus = spcs_s_kcreate();
return (ENOMEM);
if (!uparms.shadow_vol[0])
/* group or single set? */
DSW_NAMELEN) == 0)
break;
}
if (!*head) {
}
/* clear any overflow vol usage counts */
}
}
/* now increment */
}
}
/* finally, disable all group members */
rerr = 0;
while (*xnp) {
if (op) {
NO_RECLAIM : RECLAIM);
--op->ii_detachcnt;
}
/* clear out the group pointer */
if (rc) {
/* restore group name */
/* restore detachcnt */
if (op) {
++op->ii_detachcnt;
}
/* don't delete branch */
++rerr;
/* move forward in linked list */
} else {
}
}
if (rerr) {
DSW_EDISABLE));
}
/* no errors, all sets disabled, OK to free list head */
} else {
/* only a single set is being disabled */
if (rc)
}
return (0);
}
/*
* _ii_stat
* Get state of the shadow.
*
* Returns 0 on success, otherwise an error code is returned
* and any additional error information is copied out to the user.
* The size variable in the dsw_stat_t is set to the FBA size
* of the volume, the stat variable is set to the state, and
* the structure is copied out.
*/
/*ARGSUSED*/
int
{
if (ilp32) {
return (EFAULT);
return (EFAULT);
kstatus = spcs_s_kcreate();
return (ENOMEM);
if (!ustat.shadow_vol[0])
if (ilp32)
else
if (ip->bi_overflow) {
}
} else {
}
/* copy over group and cluster associations */
if (ip->bi_cluster)
if (ilp32) {
return (EFAULT);
return (EFAULT);
return (0);
}
/*
* _ii_list
* List what shadow sets are currently configured.
*
* Returns 0 on success, otherwise an error code is returned
* and any additional error information is copied out to the user.
*/
/*ARGSUSED*/
int
{
int rc;
int used;
if (ilp32) {
return (EFAULT);
return (EFAULT);
kstatus = spcs_s_kcreate();
return (ENOMEM);
ip = _ii_info_top;
if (ip->bi_disabled)
continue;
if (ilp32) {
: "<offline_bitmap>", DSW_NAMELEN);
cf32p++;
} else {
: "<offline_bitmap>", DSW_NAMELEN);
cfp++;
}
used++;
}
if (rc)
return (rc);
if (ilp32) {
return (EFAULT);
return (EFAULT);
return (0);
}
/*
* _ii_listlen
* Counts the number of items the DSWIOC_LIST and DSWIOC_OLIST
* ioctl calls would return.
*
* Returns 0 on success, otherwise an error code is returned.
* Result is returned as successful ioctl value.
*/
/*ARGSUSED*/
int
{
int count = 0;
switch (cmd) {
case DSWIOC_LISTLEN:
if (ip->bi_disabled == 0) {
count++;
}
}
break;
case DSWIOC_OLISTLEN:
count++;
break;
default:
return (EINVAL);
}
return (0);
}
/*
* _ii_report_bmp
*
* Report to the user daemon that the bitmap has gone bad
*/
static int
{
int rc;
if (!nsk) {
return (ENOMEM);
}
if (rc == 0) {
}
if (rc == 0) {
} else {
}
return (rc);
}
/*
* _ii_offline
* Set volume offline flag(s) for a shadow.
*
* Returns 0 on success, otherwise an error code is returned
* and any additional error information is copied out to the user.
*/
/*ARGSUSED*/
int
{
int rc;
if (ilp32) {
return (EFAULT);
return (EFAULT);
kstatus = spcs_s_kcreate();
return (ENOMEM);
if (!uparms.shadow_vol[0])
}
return (0);
}
/*
* _ii_wait
* Wait for a copy to complete.
*
* Returns 0 if the copy completed, otherwise error code.
*
*/
/*ARGSUSED*/
int
{
int rc = 0;
if (ilp32) {
return (EFAULT);
return (EFAULT);
kstatus = spcs_s_kcreate();
return (ENOMEM);
if (!uparms.shadow_vol[0])
/* Awoken by a signal */
break;
}
}
if (ip->bi_locked_pid == 0) {
rc = DSW_ENOTLOCKED;
ip->bi_locked_pid);
ip->bi_locked_pid = 0;
rc = DSW_EINUSE;
} else {
ip->bi_locked_pid = 0;
}
}
}
static int
{
return (DSW_COPYINGS | DSW_COPYINGP);
/* check for siblings updating master */
continue;
/* check if master is okay */
return (0);
}
}
return (DSW_COPYINGS | DSW_COPYINGP);
}
/*
* _ii_reset
* Reset offlined underlying volumes
*
* Returns 0 on success, otherwise an error code is returned
* and any additional error information is copied out to the user.
*/
/*ARGSUSED*/
int
{
int rc;
int flags;
int rtype;
if (ilp32) {
return (EFAULT);
return (EFAULT);
kstatus = spcs_s_kcreate();
return (ENOMEM);
if (!uparms.shadow_vol[0])
/* Figure out what to do according to what was flagged as */
/* Nothing offline, so no op */
return (0);
}
/* No bitmap fd, can't do anything */
return (DSW_EHDRBMP);
}
}
/*
* Cannot use _ii_bm_header_get as it will fail if DSW_BMPOFFLINE
*/
NSC_RDWRBUF, &tmp);
if (!II_SUCCESS(rc)) {
if (tmp)
(void) nsc_free_buf(tmp);
}
if (tmp)
(void) nsc_free_buf(tmp);
}
if (((flags & DSW_SHDOFFLINE) == 0) &&
/* Shadow was OK but master was offline */
/* Shadow was offline, don't care what the master was */
}
}
}
/* free any overflow allocation */
/* Bitmap now OK, so set up new bitmap header */
if (ip->bi_cluster) {
}
}
/* bitmap didn't go offline, but shadow did */
if (ip->bi_overflow) {
}
}
if (rc == 0)
if (rc == 0) {
/* just clear bitmaps for dependent copy */
if (rc == 0) {
if (rc == 0) {
}
}
}
if (rc == 0)
/*
* if copy flags were set, another process may be
* waiting
*/
if (rc == 0)
}
}
if (rc) {
if (tmp)
}
if (!II_SUCCESS(rc)) {
}
/* check with RDC */
CV_SHD2MST : 0, 1)) {
}
/* don't perform copy for dependent shadows */
}
/* _ii_copyvol calls _ii_ioctl_done() */
else {
}
}
/*
* _ii_version
* Get version of the InstantImage module.
*
* Returns 0 on success, otherwise EFAULT is returned.
* The major and minor revisions are copied out to the user if
* successful.
*/
/*ARGSUSED*/
int
{
if (ilp32) {
return (EFAULT);
return (EFAULT);
} else {
return (EFAULT);
return (EFAULT);
}
return (0);
}
/*
* _ii_copyparm
* Get and set copy parameters.
*
* Returns 0 on success, otherwise EFAULT is returned.
* The previous values are returned to the user.
*/
/*ARGSUSED*/
int
{
int rc = 0;
int tmp;
if (ilp32) {
return (EFAULT);
return (EFAULT);
kstatus = spcs_s_kcreate();
return (ENOMEM);
if (!copyp.shadow_vol[0])
else {
}
}
} else {
}
}
}
if (ilp32) {
return (EFAULT);
return (EFAULT);
}
/*
* _ii_suspend_vol
* suspend an individual InstantImage group
*
* Returns 0 on success, nonzero otherwise
*/
int
{
int copy_flag;
int rc;
return (rc);
/* this rw_enter forces us to drain all active IO */
break;
}
if (rc == 0)
/* copy over the mtime */
/* write it to disk */
}
return (rc);
}
/*
* _ii_suspend_cluster
* Cluster resource group is switching over to another node, so
* all shadowed volumes in that group are suspended.
*
* Returns 0 on success, or ESRCH if the name of the cluster resource
* group couldn't be found.
*/
int
{
/* find appropriate cluster list */
break;
}
if (!*cp) {
return (DSW_ECNOTFOUND);
}
found = 1;
last = 0;
found = 0;
if (ip->bi_disabled)
continue;
found++;
}
(void) _ii_suspend_vol(ip);
break;
}
if (found == 0)
last = 1;
}
}
return (0);
}
/*
* _ii_shutdown
* System is shutting down, so all shadowed volumes are suspended.
*
* This always succeeds, so always returns 0.
*/
/* ARGSUSED */
int
{
int found;
*rvp = 0;
_ii_shutting_down = 1;
/* Go through the list until only disabled entries are found */
found = 1;
while (found) {
found = 0;
if (ip->bi_disabled) {
/* Also covers not fully configured yet */
continue;
}
found++;
(void) _ii_suspend_vol(ip);
break;
}
if (found == 0)
}
_ii_shutting_down = 0;
return (0);
}
/*
* _ii_suspend
* Suspend an InstantImage, saving its state to allow a subsequent resume.
*
* Returns 0 if the pair was suspended. Otherwise an error code
* is returned and any additional error information is copied
* out to the user.
*/
/* ARGSUSED */
int
{
int rc;
*rvp = 0;
if (ilp32) {
return (EFAULT);
return (EFAULT);
kstatus = spcs_s_kcreate();
return (ENOMEM);
if (!uparms.shadow_vol[0])
} else {
}
}
}
}
/*
* _ii_abort
* Stop any copying process for shadow.
*
* Returns 0 if the abort succeeded. Otherwise an error code
* is returned and any additional error information is copied
* out to the user.
*/
/* ARGSUSED */
int
{
int rc;
if (ilp32) {
return (EFAULT);
return (EFAULT);
kstatus = spcs_s_kcreate();
return (ENOMEM);
if (!uabort.shadow_vol[0])
}
/*
* _ii_segment
* Copy out II pair bitmaps (cpy, shd, idx) in segments
*
* Returns 0 if the operation succeeded. Otherwise an error code
* is returned and any additional error information is copied
* out to the user.
*
*/
int
{
*rvp = 0;
if (ilp32) {
return (EFAULT);
(unsigned char *)(unsigned long)usegment32.shd_bitmap;
(unsigned char *)(unsigned long)usegment32.cpy_bitmap;
(unsigned char *)(unsigned long)usegment32.idx_bitmap;
return (EFAULT);
kstatus = spcs_s_kcreate();
return (ENOMEM);
if (usegment.shadow_vol[0]) {
} else
DSW_EEMPTY));
}
}
}
if (rc) {
}
return (0);
}
/*
* _ii_bitmap
* Copy out II pair bitmaps to user program
*
* Returns 0 if the operation succeeded. Otherwise an error code
* is returned and any additional error information is copied
* out to the user.
*/
int
{
int rc;
*rvp = 0;
if (ilp32) {
return (EFAULT);
(unsigned char *)(unsigned long)ubitmap32.shd_bitmap;
(unsigned char *)(unsigned long)ubitmap32.copy_bitmap;
return (EFAULT);
kstatus = spcs_s_kcreate();
return (ENOMEM);
if (!ubitmap.shadow_vol[0])
}
if (rc) {
}
return (0);
}
/*
* _ii_export
* Exports the shadow volume
*
* Returns 0 if the shadow was exported. Otherwise an error code
* is returned and any additional error information is copied
* out to the user.
*
* Description:
*/
int
{
int rc = 0;
*rvp = 0;
if (ilp32) {
return (EFAULT);
return (EFAULT);
kstatus = spcs_s_kcreate();
return (ENOMEM);
if (!uparms.shadow_vol[0])
/*
* Cannot export a dependent copy or while still copying or
* the shadow is already in an exported state
*/
}
}
/* this rw_enter forces us to drain all active IO */
/* Shut shadow volume. */
if (ip->bi_shdrsrv) {
}
}
if (ip->bi_shdrrsrv) {
}
}
(void) _ii_reserve_begin(ip);
if (ip->bi_shd_tok) {
}
if (ip->bi_shdr_tok) {
"raw shadow");
}
return (0);
}
/*
* _ii_join
* Rejoins the shadow volume
*
* Returns 0 if the shadow was exported. Otherwise an error code
* is returned and any additional error information is copied
* out to the user.
*
* Description:
*/
int
{
int rc = 0;
int rtype = 0;
*rvp = 0;
if (ilp32) {
return (EFAULT);
(unsigned char *)(unsigned long)ubitmap32.shd_bitmap;
return (EFAULT);
kstatus = spcs_s_kcreate();
return (ENOMEM);
if (!ubitmap.shadow_vol[0])
/*
* Check that group has shadow exported.
*/
/*
* Cannot join if the shadow isn't exported.
*/
}
/* check bitmap is at least large enough for master volume size */
/* bitmap is to small */
}
/* read in bitmap and or with differences bitmap */
}
/* open up shadow */
}
if (!rc)
if (rc) {
}
return (0);
}
/*
* _ii_ocreate
* Configures a volume suitable for use as an overflow volume.
*
* Returns 0 if the volume was configured successfully. Otherwise
* an error code is returned and any additional error information
* is copied out to the user.
*
* Description:
*/
int
{
int rc = 0;
char *overflow_vol;
*rvp = 0;
if (ilp32) {
return (EFAULT);
return (EFAULT);
kstatus = spcs_s_kcreate();
return (ENOMEM);
if (!overflow_vol[0])
if (!fd)
}
}
/* setup magic number etc; */
if (rc) {
}
/* take 1 off as chunk 0 contains header */
op->ii_drefcnt = 0;
op->ii_urefcnt = 0;
(void) nsc_release(fd);
if (rc) {
}
return (0);
}
/*
* _ii_oattach
* Attaches the volume in the "bitmap_vol" field as an overflow volume.
*
* Returns 0 if the volume was attached. Fails if the shadow group
* is of the wrong type (eg independent) or already has an overflow
* volume attached.
*
* Description:
*/
int
{
int rc = 0;
int rtype = 0;
*rvp = 0;
if (ilp32) {
return (EFAULT);
return (EFAULT);
kstatus = spcs_s_kcreate();
return (ENOMEM);
if (!uconfig.shadow_vol[0])
case NONE:
case OVR:
break;
default:
}
/* check shadow doesn't already have an overflow volume */
if (ip->bi_overflow) {
DSW_EALREADY));
}
/* check shadow is mapped so can have an overflow */
}
}
/* attach volume */
}
/* re-write header so shadow can be restarted with overflow volume */
/* detach volume */
DSW_EHDRBMP));
}
return (0);
}
/*
* _ii_odetach
* Breaks the link with the overflow volume.
*
* Returns 0 if the overflow volume was detached. Otherwise an error code
* is returned and any additional error information is copied
* out to the user.
*
* Description:
*/
int
{
int rc = 0;
int rtype = 0;
*rvp = 0;
if (ilp32) {
return (EFAULT);
return (EFAULT);
kstatus = spcs_s_kcreate();
return (ENOMEM);
if (!ubitmap.shadow_vol[0])
}
}
/* re-write header to break link with overflow volume */
DSW_EHDRBMP));
}
if (rc) {
}
return (0);
}
/*
* _ii_gc_list
* Returns a list of all lists, or all entries in a list
*
*/
int
{
int i;
*rvp = 0;
if (ilp32) {
return (EFAULT);
return (EFAULT);
kstatus = spcs_s_kcreate();
return (ENOMEM);
if (ulist.shadow_vol[ 0 ] != 0) {
/* search for specific list */
break;
}
}
if (cp) {
return (spcs_s_ocopyoutf(&kstatus,
}
}
} else {
i = 0;
}
} else {
/* return full list */
DSW_NAMELEN)) {
EFAULT));
}
}
}
if (ilp32) {
return (EFAULT);
} else {
return (EFAULT);
}
}
/*
* _ii_olist
* Breaks the link with the overflow volume.
*
* Returns 0 if the overflow volume was detached. Otherwise an error code
* is returned and any additional error information is copied
* out to the user.
*
* Description:
*/
int
{
int rc = 0;
int i;
*rvp = 0;
if (ilp32) {
return (EFAULT);
return (EFAULT);
kstatus = spcs_s_kcreate();
return (ENOMEM);
i = 0;
carg += DSW_NAMELEN) {
EFAULT));
}
i++;
}
/* return count of items listed to user */
if (ilp32) {
return (EFAULT);
} else {
return (EFAULT);
}
}
/*
* _ii_ostat
* Breaks the link with the overflow volume.
*
* Returns 0 if the overflow volume was detached. Otherwise an error code
* is returned and any additional error information is copied
* out to the user.
*
* Description:
*/
int
{
*rvp = 0;
if (ilp32) {
return (EFAULT);
return (EFAULT);
kstatus = spcs_s_kcreate();
return (ENOMEM);
if (!ustat.overflow_vol[0])
if (is_iost_2) {
}
if (ilp32) {
if (is_iost_2) {
}
return (EFAULT);
} else {
return (EFAULT);
}
return (0);
}
/*
* _ii_move_grp()
* Move a set from one group to another, possibly creating the new
* group.
*/
int
{
int rc = 0;
*rvp = 0;
if (ilp32) {
return (EFAULT);
return (EFAULT);
kstatus = spcs_s_kcreate();
return (ENOMEM);
if (!umove.shadow_vol[0])
if (!ip)
/* are we clearing the group association? */
}
} else {
/* remove it from one group and add it to the other */
if (!rc)
}
/* ** BEGIN UPDATE BITMAP HEADER ** */
}
if (bm_header) {
}
/* ** END UPDATE BITMAP HEADER ** */
}
/*
* _ii_change_tag()
* Move a set from one group to another, possibly creating the new
* group.
*/
int
{
int rc = 0;
*rvp = 0;
if (ilp32) {
return (EFAULT);
return (EFAULT);
kstatus = spcs_s_kcreate();
return (ENOMEM);
if (!umove.shadow_vol[0])
if (!ip)
/* are we clearing the group association? */
if (ip->bi_cluster) {
char *, ip->bi_cluster);
}
} else if (!ip->bi_cluster) {
/* are we adding it to a group for the first time? */
char *, ip->bi_cluster);
} else {
/* remove it from one group and add it to the other */
if (!rc)
}
/* ** BEGIN UPDATE BITMAP HEADER ** */
}
if (bm_header) {
}
/* ** END UPDATE BITMAP HEADER ** */
}
/*
* _ii_spcs_s_ocopyoutf()
* Wrapper for spcs_s_ocopyoutf() used by _ii_chk_copy() which permits
* the spcs_s_info_t argument to be NULL. _ii_chk_copy() requires this
* functionality as it is sometimes called by _ii_control_copy() which
* has no user context to copy any errors into. At all other times a NULL
* spcs_s_info_t argument would indicate a bug in the calling function.
*/
static int
{
if (ustatus)
return (err);
}
static int
{
int rc;
int rtype;
}
}
}
DSW_ECOPYING));
}
/* check if any sibling shadow is copying towards this master */
DSW_ECOPYING));
}
}
}
if (((flags & CV_SHD2MST) == 0) &&
}
}
}
if (ip->bi_locked_pid == 0) {
if (flags & CV_LOCK_PID)
}
}
}
return (0);
}
static int
{
int rc = 0;
int quick_update = 0;
/*
* a copy of a tree-mapped device must be downgraded to
* an update.
*/
flags |= CV_BMP_ONLY;
/*
* If we want to update the dependent shadow we only need to zero
* the shadow bitmap.
*/
/* assign updating time */
if (ip->bi_overflow &&
/* attempt to do a quick update */
quick_update = 1;
}
/* clean up */
}
}
if (rc == 0)
op->ii_urefcnt--;
}
if (op->ii_urefcnt == 0) {
}
}
if (rc) {
return (DSW_EIO);
} else {
return (0);
}
}
/*
* need to perform an actual copy.
*/
/*
* Perform bitmap copy if asked or from dependent shadow to master.
*/
if ((flags & CV_BMP_ONLY) ||
((flags & CV_SHD2MST) &&
} else {
}
if (rc == 0)
if (rc == 0) {
return (rc);
}
/* assign copying time */
if (flags & CV_SHD2MST)
else
} else {
}
if (waitflag)
return (rc);
}
/*
* _ii_copy
* Copy or update (take snapshot) II volume.
*
* Returns 0 if the operation succeeded. Otherwise an error code
* is returned and any additional error information is copied
* out to the user.
*/
int
{
int rc = 0;
*rvp = 0;
if (ilp32) {
return (EFAULT);
return (EFAULT);
kstatus = spcs_s_kcreate();
return (ENOMEM);
if (!ucopy.shadow_vol[0])
/* perform the copy */
/* _ii_do_copy() calls _ii_ioctl_done() */
}
return (rc);
}
/*
* _ii_mass_copy
*
* Returns 0 if the operations was successful. Otherwise an
* error code.
*/
int
{
int i;
int rc = 0;
int failed;
kstatus = spcs_s_kcreate();
return (ENOMEM);
/* Check copy validitity */
if (rc) {
/* Clean up the mess */
/*
* The array ipa now looks like:
* 0..(i-1): needs mutex_enter/ioctl_done/mutex_exit
* i: needs nothing (_ii_chk_copy does cleanup)
* (i+1)..n: needs just ioctl_done/mutex_exit
*/
failed = i;
for (i = 0; i < failed; i++) {
_ii_ioctl_done(ipa[i]);
}
/* skip 'failed', start with failed + 1 */
_ii_ioctl_done(ipa[i]);
}
return (rc);
}
}
/* Check for duplicate shadows in same II group */
/* Reset the state of all masters */
}
/*
* Check the state of the master. If DSW_MSTTARGET is
* set, it's because this master is attached to another
* shadow within this set.
*/
break;
}
/*
* Set the DSW_MSTTARGET bit on the master associated
* with this shadow. This will allow us to detect
* multiple shadows pointing to this master within
* this loop.
*/
}
}
/* Handle error */
if (rc) {
}
}
/* Lock bitmaps & prepare counts */
if (ip->bi_overflow) {
}
}
/* determine which volumes we're dealing with */
if (ip->bi_overflow) {
CV_BMP_ONLY) {
}
}
}
/* Perform copy */
/* Hum... what to do if one of these fails? */
}
/* clear out flags so as to prevent any accidental reuse */
if (ip->bi_overflow)
}
/*
* We can only clean up the kstatus structure if there are
* no waiters. If someone's waiting for the information,
* _ii_copyvolp() uses spcs_s_add to write to kstatus. Panic
* would ensue if we freed it up now.
*/
if (!wait)
return (rc);
}
/*
* _ii_list_copy
* Retrieve a list from a character array and use _ii_mass_copy to
*
* Returns 0 if the operations was successful. Otherwise an
* error code.
*/
int
{
int i;
int rc = 0;
char *name;
/* Reserve devices */
rc = DSW_ENOTFOUND;
break;
}
}
if (rc != 0) {
/* Failed to find all sets, release those we do have */
while (i-- > 0) {
}
} else {
/* Begin copy operation */
}
return (rc);
}
/*
* _ii_group_copy
* Retrieve list of sets in a group and use _ii_mass_copy to initiate
*
* Returns 0 if the operations was successful. Otherwise an
* error code.
*/
int
{
int i;
int rc;
/* find group */
name, DSW_NAMELEN) == 0)
break;
}
if (!head) {
return (DSW_EGNOTFOUND);
}
/* Count entries */
return (DSW_EGNOTFOUND);
}
return (ENOMEM);
}
/* Create list */
}
/* Begin copy operation */
return (rc);
}
/*
* _ii_acopy
* Copy or update (take snapshot) II multiple volumes.
*
* Returns 0 if the operation succeeded. Otherwise an error code
* is returned and any additional error information is copied
* out to the user.
*/
int
{
int rc;
char *list;
char *nptr;
*rvp = 0;
if (ilp32) {
return (EFAULT);
return (EFAULT);
kstatus = spcs_s_kcreate();
return (ENOMEM);
rc = 0;
EFAULT));
/* kstatus information is handled within _ii_group_copy */
ENOMEM));
EFAULT));
}
}
/*
* _ii_bitsset
* Copy out II pair bitmaps to user program
*
* Returns 0 if the operation succeeded. Otherwise an error code
* is returned and any additional error information is copied
* out to the user.
*/
int
{
int rc;
int bitmap_size;
*rvp = 0;
if (ilp32) {
return (EFAULT);
return (EFAULT);
kstatus = spcs_s_kcreate();
return (ENOMEM);
if (!ubitsset.shadow_vol[0])
DSW_EEMPTY));
}
if (cmd == DSWIOC_SBITSSET)
else
if (rc) {
}
/* return the fetched names to the user */
if (ilp32) {
} else {
}
return (rc);
}
/*
* _ii_stopvol
* Stop any copying process for shadow, and stop shadowing
*
*/
static void
{
int rc;
;
ip->bi_shd_tok = 0;
ip->bi_shdr_tok = 0;
ip->bi_mst_tok = 0;
ip->bi_mstr_tok = 0;
}
ip->bi_bmp_tok = 0;
/* Wait for any _ii_open() calls to complete */
}
if (rc) {
}
if (mst_tok) {
"master");
if (rc)
rc);
}
if (mstr_tok) {
"raw master");
if (rc)
"master %d", rc);
}
}
if (shd_tok) {
if (rc)
}
if (shdr_tok) {
if (rc)
}
if (bmp_tok) {
if (rc)
}
/* Wait for all necessary _ii_close() calls to complete */
}
}
}
/*
* _ii_ioctl_done
* If this is the last one to complete, wakeup all processes waiting
* for ioctls to complete
*
*/
static void
{
}
}
/*
* _ii_find_vol
* Search the configured shadows list for the supplied volume.
* If found, flag an ioctl in progress and return the locked _ii_info_t.
*
* The caller must check to see if the bi_disable flag is set and
* treat it appropriately.
*
* ASSUMPTION:
* _ii_info_mutex must be locked prior to calling this function
*
*/
static _ii_info_t *
{
if ((*xip)->bi_disabled)
continue;
(*xip)->bi_keyname) == 0) {
break;
}
}
if (!*xip) {
return (NULL);
}
/* Not fully configured until bi_shd_tok is set */
return (NULL);
}
return (ip);
}
static _ii_info_t *
{
}
/*
* _ii_find_overflow
* Search the configured shadows list for the supplied overflow volume.
*
*/
static _ii_overflow_t *
{
break;
}
}
if (!*xop) {
return (NULL);
}
return (op);
}
/*
* _ii_bm_header_get
* Fetch the bitmap volume header
*
*/
{
int rc;
return (NULL);
read_fba = 0;
if (!II_SUCCESS(rc)) {
if (ii_debug > 2)
rc);
if (*tmp)
(void) nsc_free_buf(*tmp);
return (NULL);
}
return (hdr);
}
/*
* _ii_bm_header_free
* Free the bitmap volume header
*
*/
/* ARGSUSED */
void
{
(void) nsc_free_buf(tmp);
}
/*
* _ii_bm_header_put
* Write out the modified bitmap volume header and free it
*
*/
/* ARGSUSED */
int
{
int rc;
write_fba = 0;
FBA_LEN(sizeof (ii_header_t)), 0);
(void) nsc_free_buf(tmp);
if (!II_SUCCESS(rc)) {
return (rc);
} else {
return (0);
}
}
/*
* _ii_flag_op
* Clear or set a flag in bi_flags and dsw_state.
* This relies on the ownership of the header block's nsc_buf
* for locking.
*
*/
void
_ii_info_t *ip;
int update;
{
/*
* No point trying to access bitmap header if it's offline
* or has been disassociated from set via DSW_HANGING
*/
if (tmp)
(void) nsc_free_buf(tmp);
return;
}
/* copy over the mtime */
}
}
}
/*
* _ii_nsc_io
* Perform read or write on an underlying nsc device
* fd - nsc file descriptor
* flag - nsc io direction and characteristics flag
* fba_pos - offset from beginning of device in FBAs
* io_addr - pointer to data buffer
* io_len - length of io in bytes
*/
int
{
int rc;
unsigned char *toaddr;
if (!II_SUCCESS(rc)) {
#ifdef DEBUG
#endif
}
#ifdef DEBUG_SPLIT_IO
#endif
loop:
#ifdef DEBUG_SPLIT_IO
#endif
#ifndef DISABLE_KSTATS
switch (ks) {
case KS_MST:
break;
case KS_SHD:
break;
case KS_BMP:
break;
case KS_OVR:
break;
default:
break;
}
}
#endif
#ifndef DISABLE_KSTATS
switch (ks) {
case KS_MST:
break;
case KS_SHD:
break;
case KS_BMP:
break;
case KS_OVR:
break;
}
}
#endif
if (!II_SUCCESS(rc)) {
if (tmp) {
(void) nsc_free_buf(tmp);
}
return (EIO);
}
/*
* Not overwriting all of the last FBA, so read in the
* old contents now before we overwrite it with the new
* data.
*/
#ifdef DEBUG_SPLIT_IO
#endif
#ifdef DISABLE_KSTATS
#else
switch (ks) {
case KS_MST:
break;
case KS_SHD:
break;
case KS_BMP:
break;
case KS_OVR:
break;
case KS_NA:
break;
default:
break;
}
#endif
if (!II_SUCCESS(rc)) {
(void) nsc_free_buf(tmp);
return (EIO);
}
}
while (tocopy > 0) {
#ifdef DEBUG
#endif
break;
}
else
if (vlen <= 0) {
vecp++;
}
}
#ifdef DISABLE_KSTATS
#else
switch (ks) {
case KS_MST:
break;
case KS_SHD:
break;
case KS_BMP:
break;
case KS_OVR:
break;
case KS_NA:
break;
default:
break;
}
#endif
if (!II_SUCCESS(rc)) {
(void) nsc_free_buf(tmp);
return (rc);
}
}
(void) nsc_free_buf(tmp);
if (fba_req > 0)
goto loop;
return (0);
}
/*
* ii_overflow_attach
*/
static int
{
int rc = 0;
int reserved = 0;
int mutex_set = 0;
/* search for name in list */
break;
}
if (op) {
op->ii_crefcnt++;
op->ii_drefcnt++;
if (!first)
if (!first)
op->ii_urefcnt++;
}
#ifndef DISABLE_KSTATS
#endif
/* write header */
}
return (rc);
}
return (ENOMEM);
}
== NULL) {
return (ENOMEM);
}
#ifndef DISABLE_KSTATS
} else {
goto fail;
}
#endif
/* open overflow volume */
goto fail;
}
goto fail;
reserved = 1;
/* register path */
_ii_ior);
goto fail;
}
/* read header */
if (!II_SUCCESS(rc)) {
goto fail;
}
/* On resume, check for old hmagic */
rc = DSW_EOMAGIC;
goto fail;
}
/* set up counts */
op->ii_drefcnt = 0;
op->ii_urefcnt = 0;
if (!first) {
/* if header version > 0, check if header written */
op->ii_urefcnt++;
}
}
op->ii_drefcnt++;
/* write header */
reserved = 0;
if (!II_SUCCESS(rc)) {
goto fail;
}
mutex_set++;
/* link onto list */
return (0);
fail:
#ifndef DISABLE_KSTATS
/* Clean-up kstat stuff */
if (op->ii_overflow) {
}
#endif
/* clean up mutex if we made it that far */
if (mutex_set) {
}
"overflow");
}
if (reserved)
}
return (rc);
}
/*
* ii_overflow_free
* Assumes that ip is locked for I/O
*/
static void
{
return;
switch (reclaim) {
case NO_RECLAIM:
if (--(op->ii_drefcnt) == 0) {
/* indicate header written */
/* write out header */
}
break;
case RECLAIM:
/* FALLTHRU */
case INIT_OVR:
if (--(op->ii_drefcnt) == 0) {
/* reset to new condition, c.f. _ii_ocreate() */
}
/* write out header */
}
if (--(op->ii_crefcnt) == 0) {
/* Close fd and unlink from active chain; */
/* NULL statement */;
if (op->ii_overflow) {
}
/* Clean up ii_overflow_t mutexs */
}
}
/*
* ii_sibling_free
* Free resources and unlink the sibling chains etc.
*/
static void
{
if (!ip)
return;
if (ip->bi_shdr_tok)
if (ip->bi_shd_tok)
} else { /* removing member of list */
break;
}
}
}
return;
}
} else {
}
/*
* Null out any pointers to shared master side resources
* that should only be freed once when the last reference
* to this master is freed and calls _ii_info_free().
*/
}
}
/*
* _ii_info_freeshd
* Free shadow side resources
*
* No mutexes should be held on entry to this function.
*
* Description:
* Frees the system resources associated with the shadow
* access, leaving the master side alone. This allows the
* original master side to continue in use while there are
* outstanding references to this _ii_info_t.
*/
static void
{
if (!ip)
return;
return; /* this work has already been completed */
if (ip->bi_cluster)
(void) II_UNLINK_CLUSTER(ip);
(void) II_UNLINK_GROUP(ip);
if (ip->bi_bmp_tok)
if (ip->bi_shdr_tok)
if (ip->bi_shd_tok)
}
}
}
}
/*
* _ii_info_free
* Free resources
*
* No mutexes should be held on entry to this function.
*
* Description:
* Frees the system resources associated with the specified
* II information structure.
*/
static void
{
if (!ip)
return;
break;
}
}
/* this rw_enter forces us to wait until all nsc_buffers are freed */
}
if (ip->bi_mstrdev) {
}
}
}
}
}
/* this rw_enter forces us to wait until all nsc_buffers are freed */
#ifdef DEBUG
#endif
}
/*
* _ii_copy_chunks
* Perform a copy of some chunks
*
* Returns 0 if the data was copied successfully, otherwise
* error code.
*
* Description:
* flag is set to CV_SHD2MST if the data is to be copied from the shadow
* to the master, 0 if it is to be copied from the master to the shadow.
*/
static int
{
int mst_flag;
int shd_flag;
int ovr_flag;
int rc;
return (EIO);
}
return (EIO);
}
if (flag == CV_SHD2MST) {
} else {
}
if (shd_chunk == II_NULLNODE) {
/* shadow is full */
return (EIO);
}
} else {
}
/*
* Always allocate the master side before the shadow to
* avoid deadlocks on the same chunk.
*/
if (!II_SUCCESS(rc)) {
if (mst_tmp)
(void) nsc_free_buf(mst_tmp);
return (rc);
}
if (ovr_flag) {
/* use overflow volume */
} else {
&shd_tmp);
}
if (!II_SUCCESS(rc)) {
(void) nsc_free_buf(mst_tmp);
if (shd_tmp)
(void) nsc_free_buf(shd_tmp);
if (ovr_flag)
if (ovr_flag)
return (rc);
}
/*
* The direction of copy is determined by the mst_flag.
*/
int, mst_flag);
if (ii_copy_direct) {
if (ovr_flag) {
} else {
}
if (!II_SUCCESS(rc)) {
/* A copy has failed - something is wrong */
if (ovr_flag)
}
} else {
if (ovr_flag) {
} else {
}
if (!II_SUCCESS(rc)) {
/*
* A failure has occurred during the above copy.
* The macro calls nsc_copy_direct, which will
* never return a read failure, only a write
* failure. With this assumption, we should
* take only the target volume offline.
*/
if (ovr_flag)
}
}
} else {
if (II_SUCCESS(rc)) {
0);
if (!II_SUCCESS(rc))
} else {
/* A copy has failed - something is wrong */
}
} else {
if (II_SUCCESS(rc)) {
if (ovr_flag) {
} else {
}
if (!II_SUCCESS(rc)) {
if (ovr_flag)
}
} else {
/* A copy has failed - something is wrong */
}
}
}
(void) nsc_free_buf(mst_tmp);
(void) nsc_free_buf(shd_tmp);
if (ovr_flag)
if (II_SUCCESS(rc)) {
rc = 0;
}
return (rc);
}
/*
* _ii_copy_on_write
*
* Returns 0 on success, otherwise error code.
*
* Description:
* Determines if a copy on write is necessary, and performs it.
* A copy on write is necessary in the following cases:
* - No copy is in progress and the shadow bit is clear, which
* means this is the first write to this track.
* - A copy is in progress and the copy bit is set, which means
* that a track copy is required.
* If a copy to the master is to be done, make a recursive call to this
* function to do any necessary copy on write on other InstantImage groups
* that share the same master volume.
*/
static int
{
int rc = 0;
int rtype;
if (hanging ||
/*
* Preserve copy of master for all other shadows of this master
* before writing our data onto the master.
*/
/*
* Avoid deadlock with COW on same chunk of sibling shadow
* by unlocking this chunk before copying all other sibling
* chunks.
*/
/*
* Only using a single chunk when copying to master avoids
* complex code here.
*/
if (!hanging)
continue;
if (xip->bi_disabled) {
continue; /* this set is stopping */
}
/* don't waste time asking for MST as ip shares it */
chunk_num, 1);
/*
* See comments in _ii_shadow_write()
*/
if (rc == 0 ||
}
}
}
if (hanging) {
return (0);
}
/*
* Reacquire chunk lock and check that a COW by a sibling
* has not already copied this chunk.
*/
if (rc < 0) {
return (EIO);
}
if (rc != 0) {
return (0);
}
}
/* Not copying at all */
/* No copy-on-write as it is independent */
return (0);
}
/* Dependent, so depends on shadow bit */
if ((flag == CV_SHD2MST) &&
/*
* Writing master but shadow is offline, so
* no need to copy on write or set shadow bit
*/
return (0);
}
return (EIO);
}
if (rc < 0) {
return (EIO);
}
if (rc == 0) {
/* Shadow bit clear, copy master to shadow */
}
} else {
/* Copying one way or the other */
return (EIO);
}
if (rc < 0) {
return (EIO);
}
if (rc) {
/* Copy bit set, do a copy */
/* Copy master to shadow */
} else {
/* Copy shadow to master */
nchunks);
}
}
}
return (rc);
}
#ifdef DEBUG
int ii_maxchunks = 0;
#endif
/*
* _ii_copyvolp()
* Copy volume process.
*
* Passes 0 back to caller when the copy is complete or has been aborted,
* otherwise error code.
*
* Description:
* According to the flag, copy the master to the shadow volume or the
* shadow to the master volume. Upon return wakeup all processes waiting
* for this copy.
*
*/
static void
{
int rc = 0;
int flag;
int chunkcount = 0;
if (ip->bi_disabled) {
rc = DSW_EABORTED;
goto skip;
}
++max_chunk;
nc_max = 1;
else {
}
#ifdef DEBUG
if (ii_maxchunks > 0)
#endif
nc_try = 1;
else
break;
/* request to abort copy */
rc = DSW_EABORTED;
break;
}
nc_got);
if (!II_SUCCESS(rc)) {
break;
}
if (ip->bi_release ||
rsrv = 0;
II_INTERNAL)) != 0) {
break;
}
rsrv = 1;
if (nc_max > 1) {
/*
* maxfbas could have changed during the
* of transfer we can do.
*/
}
}
}
skip:
else
int rs;
++bitmap_size;
bitmap_size += 7;
bitmap_size /= 8;
/* Count the number of copy bits set */
/*
* If we counted successfully and completed the copy
* see if any writes have forced the set into the
* overflow
*/
if ((rs == 0) && (shadow_set <
}
}
}
if (rsrv)
}
}
/*
* _ii_copyvol()
* Copy a volume.
*
* Returns 0 when the copy is complete or has been aborted,
* otherwise error code.
*
* Description:
* According to the flag, copy the master to the shadow volume or the
* shadow to the master volume. Upon return wakeup all processes waiting
* for this copy. Uses a separate process (_ii_copyvolp) to allow the
* caller to be interrupted.
*/
static int
int wait)
{
int rc;
/*
* start copy in separate process.
*/
return (rc);
}
if (wait == 0) {
return (0);
}
}
return (rc);
}
/*
* _ii_stopcopy
* Stops any copy process on ip.
*
* Returns 0 if the copy was stopped, otherwise error code.
*
* Description:
* Stop an in-progress copy by setting the DSW_COPYINGX flag, then
* wait for the copy to complete.
*/
static int
{
/* Awoken by a signal */
return (EINTR);
}
}
return (0);
}
/*
* _ii_error
* Given the error type that occurred, and the current state of the
* shadowing, set the appropriate error condition(s).
*
*/
void
{
int copy_flags;
int golden;
int flags;
int rc;
error_type &= ~DSW_OVERFLOW;
if ((flags ^ error_type) == 0) {
/* nothing new offline */
return;
}
if (error_type == DSW_BMPOFFLINE &&
/* first, let nskerd know */
if (rc) {
if (ii_debug > 0) {
" config DB; rc = %d", rc);
}
}
}
switch (error_type) {
case DSW_BMPOFFLINE:
/* prevent further use of bitmap */
flags |= DSW_BMPOFFLINE;
if (ii_debug > 0)
switch (copy_flags) {
case DSW_COPYINGM:
/* Bitmap offline, copying master to shadow */
flags |= DSW_SHDOFFLINE;
if (ii_debug > 0)
break;
case DSW_COPYINGS:
/* Bitmap offline, copying shadow to master */
if (golden) {
/* Shadow is still usable */
if (ii_debug > 0)
"!ii: Implied master offline");
flags |= DSW_MSTOFFLINE;
} else {
/*
* Snapshot restore from shadow to master
* is a dumb thing to do anyway. Lose both.
*/
if (ii_debug > 0)
"ii: Implied master and "
"shadow offline");
}
break;
case 0:
/* Bitmap offline, no copying in progress */
if (!golden) {
if (ii_debug > 0)
"!ii: Implied shadow offline");
flags |= DSW_SHDOFFLINE;
}
break;
}
break;
case DSW_OVROFFLINE:
flags |= DSW_OVROFFLINE;
if (ii_debug > 0)
/* FALLTHRU */
case DSW_SHDOFFLINE:
flags |= DSW_SHDOFFLINE;
if (ii_debug > 0)
if (copy_flags == DSW_COPYINGS) {
/* Shadow offline, copying shadow to master */
if (ii_debug > 0)
flags |= DSW_MSTOFFLINE;
}
break;
case DSW_MSTOFFLINE:
flags |= DSW_MSTOFFLINE;
if (ii_debug > 0)
switch (copy_flags) {
case DSW_COPYINGM:
/* Master offline, copying master to shadow */
flags |= DSW_SHDOFFLINE;
if (ii_debug > 0)
break;
case DSW_COPYINGS:
/* Master offline, copying shadow to master */
if (!golden) {
flags |= DSW_SHDOFFLINE;
if (ii_debug > 0)
"!ii: Implied shadow offline");
}
break;
case 0:
/* Master offline, no copying in progress */
if (!golden) {
flags |= DSW_SHDOFFLINE;
if (ii_debug > 0)
"!ii: Implied shadow offline");
}
break;
}
break;
default:
break;
}
if (!recursive_call &&
/* take master offline for all other sibling shadows */
continue;
continue;
/* overload DSW_OVERFLOW */
}
}
}
/*
* _ii_lock_chunk
* Locks access to the specified chunk
*
*/
static void
{
if (chunk == II_NULLCHUNK) {
} else {
return;
}
}
}
/*
* _ii_trylock_chunk
* Tries to lock access to the specified chunk
* Returns non-zero on success.
*
*/
static int
{
int rc;
return (0);
}
return (0);
}
rc = 0;
} else {
rc = 1;
}
return (rc);
}
/*
* _ii_unlock_chunks
* Unlocks access to the specified chunks
*
*/
static void
{
if (chunk == II_NULLCHUNK) {
} else {
return;
}
for (; n-- > 0; chunk++) {
}
}
}
/*
* Copyout the bit map.
*/
static int
int user_bm_size)
{
int buf_fba_len;
int buf_byte_len;
int rc;
return (EIO);
/* First calculate the size of the shadow and copy bitmaps */
return (EIO);
/*EMPTY*/;
/*EMPTY*/;
/*EMPTY*/;
else return (EIO);
/* Are we within the size of the segment being copied? */
return (EIO);
fba_pos += DSW_CBLK_FBA) {
if (!II_SUCCESS(rc)) {
if (tmp)
(void) nsc_free_buf(tmp);
return (EIO);
}
/* copyout each nsc_vec's worth of data */
buf_byte_len > 0 && user_bm_size > 0;
nsc_vecp++) {
(void) nsc_free_buf(tmp);
return (EFAULT);
}
user_bm_size -= co_len;
buf_byte_len -= co_len;
}
(void) nsc_free_buf(tmp);
}
return (0);
}
/*
* Copyin a bit map and or with differences bitmap.
*/
static int
int user_bm_size)
{
int buf_fba_len;
int buf_byte_len;
int rc;
int n;
return (EIO);
fba_pos += DSW_CBLK_FBA) {
NSC_RDWRBUF, &tmp);
if (!II_SUCCESS(rc)) {
if (tmp)
(void) nsc_free_buf(tmp);
return (EIO);
}
/* copyin each nsc_vec's worth of data */
buf_byte_len > 0 && user_bm_size > 0;
nsc_vecp++) {
(void) nsc_free_buf(tmp);
return (EFAULT);
}
for (n = ci_len; n-- > 0; /* CSTYLED */)
user_bm_size -= ci_len;
buf_byte_len -= ci_len;
}
if (!II_SUCCESS(rc)) {
(void) nsc_free_buf(tmp);
return (EIO);
}
(void) nsc_free_buf(tmp);
}
return (0);
}
/*
* Completely zero the bit map.
*
* Returns 0 if no error
* Returns non-zero if there was an error
*/
static int
{
int rc;
&tmp);
if (!II_SUCCESS(rc)) {
if (tmp)
(void) nsc_free_buf(tmp);
return (rc);
}
if (II_SUCCESS(rc)) {
}
(void) nsc_free_buf(tmp);
if (!II_SUCCESS(rc)) {
return (rc);
}
}
return (0);
}
/*
* Copy shadow bitmap to copy bitmap
*/
static int
{
int rc;
&shd_tmp);
if (!II_SUCCESS(rc)) {
if (shd_tmp)
(void) nsc_free_buf(shd_tmp);
if (ii_debug > 1)
rc);
return (rc);
}
©_tmp);
if (!II_SUCCESS(rc)) {
(void) nsc_free_buf(shd_tmp);
if (copy_tmp)
(void) nsc_free_buf(copy_tmp);
if (ii_debug > 1)
rc);
return (rc);
}
len);
if (II_SUCCESS(rc)) {
len, 0);
}
(void) nsc_free_buf(shd_tmp);
(void) nsc_free_buf(copy_tmp);
if (!II_SUCCESS(rc)) {
if (ii_debug > 1)
rc);
return (rc);
}
}
return (0);
}
/*
* stolen from nsc_copy_h()
*/
static int
{
return (EINVAL);
if (!len)
return (0);
/* find starting point in "from" vector */
/* find starting point in "to" vector */
/* copy required data */
while (len) {
for (i = sz; i-- > 0; /* CSTYLED */)
if (!l1) {
}
if (!l2) {
}
}
return (0);
}
/*
* Or the shadow bitmap in to the copy bitmap, clear the
* shadow bitmap.
*/
static int
{
int rc;
return (EIO);
if (!II_SUCCESS(rc)) {
if (shd_tmp)
(void) nsc_free_buf(shd_tmp);
return (rc);
}
if (!II_SUCCESS(rc)) {
(void) nsc_free_buf(shd_tmp);
if (copy_tmp)
(void) nsc_free_buf(copy_tmp);
return (rc);
}
len);
if (II_SUCCESS(rc)) {
len, 0);
}
if (II_SUCCESS(rc))
if (II_SUCCESS(rc)) {
0);
}
(void) nsc_free_buf(shd_tmp);
(void) nsc_free_buf(copy_tmp);
if (!II_SUCCESS(rc)) {
return (rc);
}
}
return (0);
}
/*
* _ii_ab_tst_shd_bit
* Determine if a chunk has been copied to the shadow device
*
* Returns 1 if the modified bit has been set for the shadow device,
* Returns 0 if the modified bit has not been set for the shadow device,
* Returns -1 if there was an error
*/
static int
{
int rc;
return (EIO);
if (!II_SUCCESS(rc)) {
if (tmp)
(void) nsc_free_buf(tmp);
return (-1);
}
(void) nsc_free_buf(tmp);
return (rc);
}
/*
* _ii_ab_set_shd_bit
* Records that a chunk has been copied to the shadow device
*
* Returns non-zero if an error is encountered
* Returns 0 if no error
*/
static int
{
int rc;
return (EIO);
if (!II_SUCCESS(rc)) {
if (tmp)
(void) nsc_free_buf(tmp);
return (rc);
}
ip->bi_shdbits++;
}
(void) nsc_free_buf(tmp);
if (!II_SUCCESS(rc)) {
return (rc);
}
return (0);
}
/*
* _ii_ab_tst_copy_bit
* Determine if a chunk needs to be copied during updates.
*
* Returns 1 if the copy bit for the chunk is set
* Returns 0 if the copy bit for the chunk is not set
* Returns -1 if an error is encountered
*/
static int
{
int rc;
return (-1);
if (!II_SUCCESS(rc)) {
if (tmp)
(void) nsc_free_buf(tmp);
return (-1);
}
(void) nsc_free_buf(tmp);
return (rc);
}
/*
* _ii_ab_set_copy_bit
* Records that a chunk has been copied to the shadow device
*
* Returns non-zero if an error is encountered
* Returns 0 if no error
*/
static int
{
int rc;
return (EIO);
if (!II_SUCCESS(rc)) {
if (tmp)
(void) nsc_free_buf(tmp);
return (rc);
}
ip->bi_copybits++;
}
(void) nsc_free_buf(tmp);
if (!II_SUCCESS(rc)) {
return (rc);
}
return (0);
}
/*
* _ii_ab_clr_copy_bits
* Records that a chunk has been cleared on the shadow device, this
* function assumes that the bits to clear are all in the same fba,
* as is the case when they were generated by _ii_ab_next_copy_bit().
*
* Returns non-zero if an error is encountered
* Returns 0 if no error
*/
static int
{
int rc;
return (EIO);
if (!II_SUCCESS(rc)) {
if (tmp)
(void) nsc_free_buf(tmp);
return (rc);
}
if (ip->bi_copybits > 0)
ip->bi_copybits--;
}
(void) nsc_free_buf(tmp);
if (!II_SUCCESS(rc)) {
return (rc);
}
return (0);
}
/*
* _ii_ab_fill_copy_bmp
* Fills the copy bitmap with 1's.
*
* Returns non-zero if an error is encountered
* Returns 0 if no error
*/
static int
{
int rc;
unsigned char *p;
int i, j;
return (EIO);
if (!II_SUCCESS(rc)) {
if (tmp)
(void) nsc_free_buf(tmp);
return (rc);
}
for (j = FBA_SIZE(1); j-- > 0; p++)
*p = (unsigned char)0xff;
if (!II_SUCCESS(rc)) {
(void) nsc_free_buf(tmp);
return (rc);
}
(void) nsc_free_buf(tmp);
}
return (0);
}
/*
* _ii_ab_load_bmp
* Load bitmap from persistent storage.
*/
static int
/* ARGSUSED */
{
return (EIO);
return (0);
}
/*
* _ii_ab_next_copy_bit
* Find next set copy bit.
*
* Returns the next bits set in the copy bitmap, with the corresponding chunks
* locked. Used to avoid having to reread the same bit map block as each bit
* is tested.
*/
static chunkid_t
{
int high;
*got = 0;
return (maxchunk + 1);
while (startchunk < maxchunk) {
if (!II_SUCCESS(rc)) {
if (tmp)
(void) nsc_free_buf(tmp);
return (maxchunk + 1);
}
/*
* trylock won't sleep so can use while
* holding the buf.
*/
(void) nsc_free_buf(tmp);
!= 1) {
/*
* another process copied this
* chunk while we were acquiring
* the chunk lock.
*/
goto again;
}
*got = 1;
return (startchunk);
}
*got = 1;
chunk++;
break; /* end of bit run */
}
(*got)++;
else
break;
}
(void) nsc_free_buf(tmp);
return (startchunk);
}
}
(void) nsc_free_buf(tmp);
}
return (maxchunk + 1);
}
/*
* _ii_ab_save_bmp
* Save bitmap to persistent storage.
*/
static int
/* ARGSUSED */
{
return (EIO);
return (0);
}
/*
* _ii_ab_change_bmp
* copy change bitmap to memory
*/
static int
/* ARGSUSED */
{
int bm_size;
int i, j, fba;
int rc;
unsigned char *p;
return (EIO);
if (!II_SUCCESS(rc)) {
return (rc);
}
if (!II_SUCCESS(rc)) {
if (tmp)
(void) nsc_free_buf(tmp);
return (rc);
}
for (j = FBA_SIZE(1); j-- > 0; p++)
*ptr |= *p;
(void) nsc_free_buf(tmp);
}
return (0);
}
/*
* Count bits set in the bit map.
*/
static int
int bm_size)
{
int buf_fba_len;
int buf_byte_len;
int co_len;
int i;
unsigned int j, k;
unsigned char *cp;
int rc;
*counter = 0;
return (EIO);
fba_pos += DSW_CBLK_FBA) {
if (!II_SUCCESS(rc)) {
if (tmp)
(void) nsc_free_buf(tmp);
return (EIO);
}
/* count each sd_vec's worth of data */
buf_byte_len > 0 && bm_size > 0;
sd_vecp++) {
for (i = k = 0; i < co_len; i++)
for (j = (unsigned)*cp++; j; j &= j - 1)
k++;
*counter += k;
buf_byte_len -= co_len;
}
(void) nsc_free_buf(tmp);
}
return (0);
}
/*
* OR the bitmaps as part of a join operation
*/
static int
{
int rc;
return (EIO);
src_fba_pos += DSW_CBLK_FBA) {
NSC_RDWRBUF, &src_tmp);
if (!II_SUCCESS(rc)) {
if (src_tmp)
(void) nsc_free_buf(src_tmp);
return (rc);
}
NSC_RDWRBUF, &dest_tmp);
if (!II_SUCCESS(rc)) {
(void) nsc_free_buf(src_tmp);
if (dest_tmp)
(void) nsc_free_buf(dest_tmp);
return (rc);
}
len);
if (II_SUCCESS(rc)) {
src_fba_pos, len, 0);
}
(void) nsc_free_buf(src_tmp);
(void) nsc_free_buf(dest_tmp);
if (!II_SUCCESS(rc)) {
return (rc);
}
}
return (0);
}
};
/*
* Copyout the bit map.
*/
static int
int user_bm_size)
{
int start_offset;
int bm_size;
/* First calculate the size of the shadow and copy bitmaps */
return (EIO);
/*EMPTY*/;
/*EMPTY*/;
/*EMPTY*/;
else return (EIO);
return (EIO);
return (EFAULT);
return (0);
}
/*
* Copyin a bit map and or with differences bitmap.
*/
static int
int user_bm_size)
{
unsigned char *tmp_buf;
unsigned char *dest;
unsigned char *p;
int n;
int start_offset;
int bm_size;
int rc = 0;
while (ci_len > 0) {
break;
}
user_bm += n;
*dest++ |= *p++;
}
if (tmp_buf)
return (rc);
}
/*
* Completely zero the bit map.
*/
static int
{
int len;
return (0);
}
/*
* Copy shadow bitmap to copy bitmap
*/
static int
{
int len;
return (0);
}
/*
* Or the shadow bitmap in to the copy bitmap, clear the
* shadow bitmap.
*/
static int
{
int len;
while (len-- > 0)
return (0);
}
/*
* _ii_km_tst_shd_bit
* Determine if a chunk has been copied to the shadow device
*
* Returns 1 if the modified bit has been set for the shadow device,
* otherwise returns 0.
*/
static int
{
unsigned char *bmp;
int bmp_offset;
int rc;
return (rc);
}
/*
* _ii_km_set_shd_bit
* Records that a chunk has been copied to the shadow device
*/
static int
{
unsigned char *bmp;
int bmp_offset;
ip->bi_shdbits++;
}
return (0);
}
/*
* _ii_km_tst_copy_bit
* Determine if a chunk needs to be copied during updates.
*
* Returns 1 if the copy bit for the chunk is set,
* otherwise returns 0
*/
static int
{
unsigned char *bmp;
int bmp_offset;
int rc;
return (rc);
}
/*
* _ii_km_set_copy_bit
* Records that a chunk has been copied to the shadow device
*/
static int
{
unsigned char *bmp;
int bmp_offset;
ip->bi_copybits++;
}
return (0);
}
/*
* _ii_km_clr_copy_bits
* Records that a chunk has been cleared on the shadow device
*/
static int
{
unsigned char *bmp;
int bmp_offset;
if (ip->bi_copybits > 0)
ip->bi_copybits--;
}
return (0);
}
/*
* _ii_km_fill_copy_bmp
* Fills the copy bitmap with 1's.
*/
static int
{
int len;
unsigned char *bmp;
int bmp_offset;
while (len-- > 0)
*bmp++ = (unsigned char)0xff;
return (0);
}
/*
* _ii_km_load_bmp
* Load bitmap from persistent storage.
*/
static int
{
int rc;
return (EIO);
}
if (flag)
return (0); /* just create an empty bitmap */
if (!II_SUCCESS(rc))
return (rc);
}
/*
* _ii_km_save_bmp
* Save bitmap to persistent storage.
*/
static int
{
int bmp_offset;
int bitmap_size;
int rc;
else {
if (!II_SUCCESS(rc))
}
}
return (rc);
}
/*
* _ii_km_next_copy_bit
* Find next set copy bit.
*
* Returns the next bits set in the copy bitmap, with the corresponding chunks
* locked. Used to cut down on the number of times the bmpmutex is acquired.
*/
static chunkid_t
{
unsigned char *bmp;
int bmp_offset;
int nextchunk;
*got = 0;
/*
* trylock won't sleep so can use while
* holding bi_bmpmutex.
*/
*got = 1;
return (chunk);
}
*got = 1;
break;
(*got)++;
else
break;
}
return (chunk);
}
}
return (maxchunk + 1);
}
/*
* _ii_km_change_bmp
* copy change bitmap to memory
*/
static int
/* ARGSUSED */
{
int start_offset;
int bm_size;
unsigned char *q;
while (bm_size-- > 0)
*ptr |= *q;
return (0);
}
/*
* Count bits set in the bit map.
*/
static int
int bm_size)
{
int start_offset;
int i;
nsc_size_t j, k;
unsigned char *cp;
for (i = k = 0; i < bm_size; i++)
for (j = (unsigned)*cp++; j; j &= j - 1)
k++;
*counter = k;
return (0);
}
/*
* Or the shadow bitmap in to the copy bitmap, clear the
* shadow bitmap.
*/
static int
{
while (bm_size-- > 0)
return (0);
}
};
static int
{
int rc;
int overflow;
/* simple read with optional copy */
if (mst_src) {
} else {
}
}
return (rc);
}
/* read from mapped shadow into final buffer */
if (mapped_chunk == II_NULLNODE)
return (EIO);
if (overflow)
/* convert chunk number from tsearch into final fba */
if (overflow) {
} else {
}
if (II_SUCCESS(rc)) {
(void) nsc_free_buf(tmp);
}
if (overflow)
return (rc);
}
/*
* _ii_fill_buf
* Read data from the required device
*
* Returns 0 if the data was read successfully, otherwise
* error code.
*
* Description:
* Reads the data from fba_pos for length fba_len from the
* required device. This data may be a mix of data from the master
* device and the shadow device, depending on the state of the
* bitmaps.
*/
static int
{
int second_shd = 0;
int rc;
int fill_from_pair;
if (flag&NSC_RDAHEAD)
return (NSC_DONE);
/*
* If the master is being updated from a shadow we need to fill from
* the correct shadow volume.
*/
continue;
second_shd = 1;
II_INTERNAL)) != 0)
return (EIO);
if (!II_SUCCESS(rc)) {
goto out;
}
handle2 = &second_buf;
break;
}
}
}
while (temp_len > 0) {
} else {
temp_len = 0;
}
fill_from_pair = 0;
/* Treat a failed bitmap volume as a clear bit */
if (rc > 0) {
/* Copy bit set */
if (*handle2)
fill_from_pair = 1;
else {
goto out;
}
}
}
}
/* Treat a failed bitmap volume as a clear bit */
if (rc > 0) {
/* Copy bit set */
if (*handle2 ||
fill_from_pair = 1;
else {
goto out;
}
}
}
}
/* Dependent shadow read */
if (rc < 0) {
goto out;
}
if (rc == 0) {
/* Shadow bit clear */
if (*handle2)
fill_from_pair = 1;
else {
goto out;
}
}
}
if (fill_from_pair) {
/* it matters now */
goto out;
}
goto out;
}
if (!II_SUCCESS(rc)) {
goto out;
}
} else {
goto out;
}
goto out;
}
if (!II_SUCCESS(rc)) {
else
goto out;
}
}
chunk_num++;
}
rc = 0;
out:
if (second_buf)
(void) nsc_free_buf(second_buf);
if (second_shd)
return (rc);
}
/*
* _ii_shadow_write
* Perform any copy on write required by a write buffer request
*
* Returns 0 on success, otherwise error code.
*
*/
static int
{
int rc;
int flag;
int hanging;
/* fail immediately if config DB is unavailable */
return (EIO);
}
flag = 0; /* To shadow */
else
for (; (chunk_num >= 0) &&
if (!hanging)
/*
* Set the shadow bit when a small shadow has overflowed so
* that ii_read_volume can return an error if an attempt is
* made to read that chunk.
*/
if (!hanging) {
if (rc == 0 ||
}
}
}
}
/* did the bitmap fail during this process? */
}
/*
* _ii_alloc_buf
* Allocate a buffer of data
*
* Returns 0 for success, < 0 for async I/O, > 0 is an error code.
*
* Description:
* For a write buffer, calls dsw_shadow_write to perform any necessary
* copy on write operations, then allocates the real buffers from the
* underlying devices.
* For a read buffer, allocates the real buffers from the underlying
* devices, then calls _ii_fill_buf to fill the required buffer.
* For a buffer that is neither read nor write, just allocate the
* buffers so that a _ii_fill_buf can be done later by _ii_read.
*/
static int
{
ii_buf_t *h;
int rc = 0;
int ioflag;
int rw_ent = 0;
/* any I/O to the bitmap device is barred */
return (EIO);
}
if (len == 0) {
return (EINVAL);
}
/* Bounds checking */
if (ii_debug > 1)
"!ii: Attempt to access beyond end of ii volume");
return (EIO);
}
h = *ptr;
if (h == NULL) {
if (h == NULL) {
return (ENOMEM);
}
}
/*
* Temporary nsc_reserve of bitmap and other device.
* This device has already been reserved by the preceding _ii_attach.
* Corresponding nsc_release is in _ii_free_buf.
*/
rw_ent = 1;
rw_ent = 0;
goto error;
}
if (!II_SUCCESS(rc))
goto error;
}
if (!(flag & NSC_RDAHEAD))
else
/*
* SHADOW
*/
goto error;
}
/*
* The master device buffer has to be allocated first
* so that deadlocks are avoided.
*/
if (!II_SUCCESS(rc)) {
if (ii_debug > 2)
if (h->ii_bufp2)
(void) nsc_free_buf(h->ii_bufp2);
/*
* Carry on as this will not matter if
* _ii_fill_buf is not called, or if
* it is called but doesn't need to read this
* volume.
*/
rc = 0;
}
fbuf2 = 1;
}
goto error;
}
if (!II_SUCCESS(rc)) {
goto error;
}
abuf = 1;
} else {
if (!II_SUCCESS(rc)) {
goto error;
}
fbuf = 1;
}
} else {
/*
* MASTER
*/
/*
* The master device buffer has to be allocated first
* so that deadlocks are avoided.
*/
goto error;
}
&h->ii_bufp); /* do not read yet */
if (!II_SUCCESS(rc)) {
goto error;
}
fbuf = 1;
/*
* If shadow FD and (dependent set OR copying) and
* not (compact dependent && shadow offline && shadow exported)
*/
if (!II_SUCCESS(rc)) {
if (ii_debug > 2)
if (h->ii_bufp2)
(void) nsc_free_buf(h->ii_bufp2);
/*
* Carry on as this will not matter if
* _ii_fill_buf is not called, or if
* it is called but doesn't need to read this
* volume.
*/
rc = 0;
}
fbuf2 = 1;
}
}
if (II_SUCCESS(rc)) {
} else {
(void) nsc_free_buf(h->ii_bufp2);
}
(void) nsc_free_buf(h->ii_bufp);
}
(void) nsc_free_buf(h->ii_abufp);
}
if (h->ii_rsrv) {
/*
* Release temporary reserve - reserved above.
*/
}
if (rw_ent)
}
return (rc);
}
/*
* _ii_free_buf
*/
static int
{
int rsrv;
int rc;
} else {
}
if (!II_SUCCESS(rc))
return (rc);
if (h->ii_bufp2) {
if (!II_SUCCESS(rc))
return (rc);
}
if (!II_SUCCESS(rc))
return (rc);
} else {
}
/*
* Release temporary reserve - reserved in _ii_alloc_buf.
*/
if (rsrv)
return (0);
}
/*
* _ii_open
* Open a device
*
* Returns a token to identify the shadow device.
*
* Description:
* Performs the housekeeping operations associated with an upper layer
* of the nsc stack opening a shadowed device.
*/
/* ARGSUSED */
static int
{
int is_mst = 0;
int is_shd = 0;
if (!bfd)
return (ENOMEM);
is_mst = 1;
break;
is_shd = 1;
break;
break;
}
if (is_mst)
return (EINTR);
}
if (!ip) {
/* maybe it's an overflow */
break;
}
if (!op) {
return (EINVAL);
}
return (0);
}
if (is_mst) {
if (raw) {
ip->bi_mstrref++;
} else {
}
} else if (is_shd) {
if (raw) {
ip->bi_shdrref++;
} else {
}
} else {
}
return (0);
}
static int
{
}
static int
{
}
/*
* _ii_close
* Close a device
*
* Always succeeds - returns 0
*
* Description:
* Performs the housekeeping operations associated with an upper layer
* of the nsc stack closing a shadowed device.
*/
static int
{
int raw;
if (!ip) {
return (0);
}
} else if (raw) {
} else {
}
if (dip) {
}
}
return (0);
}
/*
* _ii_alloc_handle
* Allocate a handle
*
*/
static nsc_buf_t *
{
ii_buf_t *h;
return (NULL);
h = kmem_alloc(sizeof (*h), KM_SLEEP);
if (!h)
return (NULL);
if (!h->ii_bufp) {
kmem_free(h, sizeof (*h));
return (NULL);
}
return ((nsc_buf_t *)h);
}
/*
* _ii_free_handle
* Free a handle
*
*/
static int /*ARGSUSED*/
{
int rc;
if (h->ii_abufp)
(void) nsc_free_buf(h->ii_abufp);
if (!II_SUCCESS(rc)) {
return (rc);
}
return (0);
}
/*
* _ii_attach
* Attach
*
* Returns 0 for success, errno on failure.
*
* Description:
*/
static int
{
int dev;
int raw;
int rc;
int, raw);
return (EINVAL);
return (EINVAL);
if (raw) {
} else {
}
if (raw) {
} else {
}
}
if (iodev) {
}
return (EINVAL);
if (raw)
else
return (rc);
}
/*
* _ii_detach
* Detach
*
* Returns 0 for success, always succeeds
*
* Description:
*/
static int
{
int dev;
int raw;
int, raw);
return (0);
return (0);
}
/*
* _ii_get_pinned
*
*/
static int
{
int rc;
return (EIO);
return (rc);
}
/*
* _ii_discard_pinned
*
*/
static int
{
int rc;
return (EIO);
return (rc);
}
/*
* _ii_partsize
*
*/
static int
{
/* Always return saved size */
return (0);
}
/*
* _ii_maxfbas
*
*/
static int
{
int rc;
int rs;
int dev;
return (EIO);
if (rs == 0)
return (rc);
}
/*
* ii_get_group_list
*/
_ii_info_t **
{
int i;
int nip;
group, DSW_NAMELEN) == 0)
break;
}
if (!head) {
return (NULL);
}
/* Count entries */
++nip;
for (i = 0; i < nip; i++) {
}
return (ipa);
}
/*
* _ii_pinned
*
*/
static void
{
}
/*
* _ii_unpinned
*
*/
static void
{
}
/*
* _ii_read
*/
static int
{
int rc;
void *sb_vec;
else {
}
if (!II_SUCCESS(rc))
return (rc);
}
/*
* _ii_write
*/
static int
{
int rc;
int overflow;
void *sb_vec;
flag);
} else {
flag);
}
} else {
/* write of mapped shadow buffer */
rc = 0;
/*
* don't need to test bitmaps as allocating the
* write buffer will c-o-write the chunk.
*/
if (mapped_chunk == II_NULLNODE) {
break;
}
if (overflow)
if (overflow) {
} else
if (II_SUCCESS(rc)) {
}
if (overflow) {
} else {
}
(void) nsc_free_buf(tmp);
if (overflow)
/* move on to next chunk */
chunk_num++;
}
}
if (!II_SUCCESS(rc))
return (rc);
}
/*
* _ii_zero
*/
static int
{
int rc;
void *sb_vec;
if (!II_SUCCESS(rc))
return (rc);
}
/*
* _ii_uncommit
*/
static int
{
int rc;
void *sb_vec;
if (!II_SUCCESS(rc))
return (rc);
}
/*
* _ii_trksize
*/
static int
{
int rc;
return (rc);
}
/*
* _ii_register_path
*/
static nsc_path_t *
{
return (tok);
}
/*
* _ii_unregister_path
*/
/*ARGSUSED*/
static int
{
int rc;
return (rc);
}
int
char **key)
{
if (!node) {
return (ENOMEM);
}
/* find out where we should insert it */
break;
}
}
if (!*head) {
/* create a new entry */
if (!*head) {
/* bother */
return (ENOMEM);
}
}
return (0);
}
int
{
int found;
break;
}
if (!*head) {
/* no such link (!) */
return (0);
}
found = 0;
found = 1;
break;
}
}
if (!found) {
return (0);
}
/* did we just delete the last set in this resource group? */
}
return (0);
}
0, 0, 0
};
"Provide", 0, 0,
0, 0, 0
};
"Provide", 0, 0,
0, 0, 0
};