sd_pcu.c revision fcf3ce441efd61da9bb2884968af01cb7c1452cc
/*
* 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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/nsc_thread.h>
#include "sd_bcache.h"
#include "sd_trace.h"
#include "sd_io.h"
#include "sd_bio.h"
#include "sd_ft.h"
#include "sd_misc.h"
#include "sd_pcu.h"
/*
* PCU (aka UPS) handling -
*/
#define bitmap_next cc_dirty_link
#define bitmap_tail cc_dirty_next
#define anon_next cc_dirty_link
#define anon_tail cc_dirty_next
struct bitmap {
int bmaps_per_block;
int inuse; /* In use in the _last_ block */
};
struct swapfiles {
int nswpf; /* Number of filenames */
int colsize; /* In cache blocks */
char *names[SDBC_PCU_MAXSWAPIL];
};
static void _sdbc_pcu_cleanup(struct swapfiles *);
/*
* Forward declare functions containing 64-bit argument types to enforce
* type-checking.
*/
static int got_hint; /* did we capture hint at power_lost */
static unsigned int wrthru_hint; /* saved hint at power_lost */
static int saw_power_lost;
/*
* sdbc_get_anon_list - allocate a set of anonymous cache block
* entries that can pretend to be a single blocks of data holding
* a virtual character array holding "bytes" entries.
*
* returns - the cache block heading the chain.
*/
static _sd_cctl_t *
{
nsc_size_t i, blks;
for (i = 0; i < blks; i++) {
};
return (list);
}
/*
* sdbc_anon_get - gets "len" bytes of data virtual character array represented
* by "src" begining at index "dest_off" and copy to buffer "dest".
*
* dest - pointer to our virtual array (chain of cache blocks).
* dest_off - first location to copy data to.
* src - pointer to data to copy
* len - the number of bytes of data to copy
*
*/
static void
{
nsc_size_t i;
if (len == 0)
return;
for (i = 0; i < blk_start; i++) {
}
nlen += CACHE_BLOCK_SIZE;
}
}
}
/*
* sdbc_anon_copy - copies "len" bytes of data from "src" to the
* virtual character array represented by "dest" begining at index
* "dest_off".
*
* src - pointer to data to copy
* len - the number of bytes of data to copy
* dest - pointer to our virtual array (chain of cache blocks).
* dest_off - first location to copy data to.
*
*/
static void
{
nsc_size_t i;
if (len == 0)
return;
for (i = 0; i < blk_start; i++) {
}
nlen += CACHE_BLOCK_SIZE;
}
}
}
/*
* flush_anon_list - flush a chain of anonymous cache blocks
* to the state file. Anonymous chains of cache blocks represent
* virtual arrays for the state flushing code and can contain
* various types of data.
*
* anon_list - chain of cache blocks to flush.
*
* dev - the state file device
*
* blkno - on input the cache block number to begin writing at.
* On exit the next cache block number following the data
* just written.
*
* returns - 0 on success, error number on failure.
*/
static int
{
int rc;
return (0);
bcnt = 0;
do {
BLK_TO_FBA_NUM(1), 0);
(*blkno)++;
/*
* A failure here is death. This is harsh but not sure
* what else to do
*/
return (rc);
bcnt++;
} while (anon_list);
return (0);
}
/*
* start_bitmap_list - allocate an anonymous cache block entry
* to anchor a chain of cache blocks representing a virtual
* array of bitmap entries.
*
* returns - the cache block heading the chain.
*/
static void
{
}
/*
* add_bitmap_entry - Add a bitmap entry to the chain of bitmap
* entries we are creating for cd's entry in the state file.
*
* Bitmaps are stored in a chain of anonymous cache blocks. Each
* cache block can hold bmaps_per_block in it. As each block is
* filled a new block is added to the tail of the chain.
*
* list - the chain of cache blocks containing the bitmaps.
* bits - the bitmap entry to add.
* any_fail - flag saying whether the data corresponding to this
* bitmap entry had previously failed going to disk.
* fba_num - FBA number corresponding to the entry.
*
* returns - 0 on success, error number on failure.
*/
static int
{
int i;
}
return (0);
}
/*
* flush_bitmap_list - flush a chain of anonymous cache blocks
*
* b_list - the chain of bitmap data.
* dev - the state file device.
* blkno - on input the cache block number to begin writing at.
* On exit the next cache block number following the data
* just written.
*
* returns - 0 on success, error number on failure.
*/
static int
{
int rc;
int bcnt = 0; /* P3 temp */
return (0);
do {
BLK_TO_FBA_NUM(1), 0);
(*blkno)++;
/*
* A failure here is death. This is harsh but not sure
* what else to do
*/
return (rc);
bcnt++;
} while (b_list);
return (0);
}
/*
* flush_centry_list - flush a chain of cache blocks for the
* cache descriptor described by "cdi" to the state file.
* In addition the bitmaps describing the validity and dirty
* state of each entry are captured to the bitmap chain.
*
* cdi - pointer to description of the cd we are writing.
* dirty - chain of dirty cache blocks to flush (linked
* by dirty_next (sequential) and dirty_link (disjoint).
*
* dev - the state file device.
*
* blkno - on input the cache block number to begin writing at.
* On exit the next cache block number following the data
* just written.
*
* failed - a flag noting whether these blocks had already
* been attempted to write to their true destination and
* failed. (i.e. is the chain from fail_head).
*
* bmaps - a chain of anonymous cache blocks containing all
*
* returns - 0 on success, error number on failure.
*/
static int
int failed,
{
int rc;
int bcnt = 0;
return (0);
do {
/*
* each cache block is written to the disk regardless of its
*/
count = 0;
do {
count++;
} while (cc_ent);
BLK_TO_FBA_NUM(count), 0);
do {
if (rc)
return (rc);
} while (cc_ent);
/*
* A failure here is death. This is harsh but not sure
* what else to do
*/
return (rc);
} while (dirty);
return (0);
}
/*
* flush_hdr - Flush the state file header to the disk partition
* "dev" at FBA "blkno". Return the result of the i/o operation.
* hdr - a cache block containing the header.
* dev - the state file device.
* blkno - cache block position to write the header.
*
* returns - 0 on success, error number on failure.
*/
static int
{
int rc;
return (rc);
}
/*
* _sdbc_power_flush - flushd the state of sdbc to the state "file"
* on the system disk. All dirty blocks (in progress, unscheduled,
* failed) are written along with the bitmap for each block. The
* data is written using normal sdbc i/o via anonymous cache blocks.
* This is done to simplify the job here (and to limit memory
* requests) at the expense of making the recovery programs more
* complex. Since recovery is done at user level this seems to be
* a good trade off.
*
* Returns: 0 on success, error number on failure.
*/
static int
_sdbc_power_flush(void)
{
int string_size;
int open_files;
long len;
long total_len;
int pending;
int rc = 0;
/*
* Force wrthru just in case SLM software didn't really send us a
* warning. (Also makes for easier testing)
*/
(void) _sd_set_node_hint(NSC_FORCED_WRTHRU);
/* disable all (dangerous) cache entry points */
#if 0
/*
* this is bad, in theory we could just busy-out all our
* interfaces and continue.
*/
"sdbc(_sdbc_power_flush) couldn't unregister i/o %d", rc);
return (rc);
}
#endif
if ((pending = _sdbc_wait_pending()) != 0)
" pending at power shutdown", pending);
/* prevent any further async flushing */
/*
* At this point no higher level clients should be able to get thru.
* Failover i/o from the other node is our only other concern as
* far as disturbing the state of sdbc.
*/
/* figure out the names for the string pool */
string_size = 0;
open_files = 0;
do {
continue;
continue;
open_files++;
if (open_files == 0) {
return (0);
}
/* XXX bmap_size is redundant */
open_files = 0;
total_len = 0;
do {
continue;
continue;
/* copy the name to string pool */
open_files * sizeof (sdbc_pwf_desc_t));
open_files++;
/* flush dirty data */
" is not configured");
goto cleanup;
}
if (!(state_fd =
if (state_fd) {
}
/*
* We are hosed big time. We can't get device to write the
* state file opened.
*/
goto cleanup;
}
blkno = 1;
/*
* iterate across all devices, flushing the data and collecting bitmaps
*/
open_files = 0;
for (cdi = _sd_cache_files;
continue;
continue;
/* retrieve the file description so we can update it */
if (cdi->cd_io_head) {
/*
* Need to wait for this to timeout?
* Seems like worst case we just write the data twice
* so we should be ok.
*/
/*EMPTY*/
;
}
/* Flush the enqueued dirty data blocks */
/* Flush the failed dirty data blocks */
/*
* Flush the in progress dirty data blocks. These really should
* really be null by now. Worst case we write the data again
* on recovery as we know the dirty masks won't change since
* flusher is stopped.
*/
/* update the current cd's file description */
fp_off);
}
#if !defined(_SunOS_5_6)
#else
#endif
/* write the header at front and back */
/* P3 */
blkno);
;
return (rc);
}
/*
* _sdbc_power_lost - System is running on UPS power we have "rideout"
* minutes of power left prior to shutdown. Get into a state where we
* will be ready should we need to shutdown.
*
* ARGUMENTS:
* rideout - minutes of power left prior to shutdown.
*/
void
_sdbc_power_lost(int rideout)
{
"remaining %d minute(s)", rideout);
got_hint = 1;
if (_sd_get_node_hint(&wrthru_hint))
got_hint = 0;
(void) _sd_set_node_hint(NSC_FORCED_WRTHRU);
saw_power_lost = 1;
}
/*
* _sdbc_power_ok - System is back running on mains power after
* seeing a power fail. Return to normal power up operation.
*
*/
void
_sdbc_power_ok(void)
{
if (saw_power_lost && got_hint) {
/*
* In theory we have a race here between _sdbc_power_lost
* and here. However it is expected that power ioctls that
* cause these to be generated are sequential in nature
* so there is no race.
*/
saw_power_lost = 0;
if (wrthru_hint & _SD_WRTHRU_MASK)
else
(void) _sd_clear_node_hint(_SD_WRTHRU_MASK);
}
}
/*
* _sdbc_power_down - System is running on UPS power and we must stop
* operation as the machine is now going down. Schedule a shutdown
* thread.
*
* When we return all cache activity will be blocked.
*/
void
_sdbc_power_down(void)
{
(void) _sdbc_power_flush();
}
/*
* Configure safe store from the general cache configuration ioctl.
*/
int
{
int i;
/*
* This should not happen because cache protects itself
* from double configuration in sd_conf.c.
*/
"configuration of Safe Store\n");
return (EINVAL);
}
for (i = 0; i < namec; i++) {
KM_NOSLEEP)) == NULL) {
return (ENOMEM);
}
}
return (0);
}
/*
*/
void
{
}
/*
* Destructor for struct swapfiles.
*/
static void
{
int i;
char *s;
}
}