sd_bcache.h 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.
*/
#ifndef _SD_BCACHE_H
#define _SD_BCACHE_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef DS_DDICT
#endif
/*
* Definitions for kstats
*/
#define SDBC_KSTAT_CLASS "storedge"
#define SDBC_KSTAT_MODULE "sdbc"
#ifdef DEBUG
#define SDBC_KSTAT_DYNMEM "dynmem"
#endif
#define SDBC_KSTAT_CDNAME "cdname"
#define SDBC_KSTAT_CDSTATS "cd"
#define SDBC_KSTAT_GSTATS "global"
#define SDBC_KSTAT_STATS "sdbcstats"
#define SDBC_IOKSTAT_GSTATS "gsdbc"
#define SDBC_IOKSTAT_CDSTATS "sdbc"
/* Global kstat field names */
#define SDBC_GKSTAT_COUNT "sdbc_count"
#define SDBC_GKSTAT_LOC_COUNT "sdbc_loc_count"
#define SDBC_GKSTAT_RDHITS "sdbc_rdhits"
#define SDBC_GKSTAT_RDMISS "sdbc_rdmiss"
#define SDBC_GKSTAT_WRHITS "sdbc_wrhits"
#define SDBC_GKSTAT_WRMISS "sdbc_wrmiss"
#define SDBC_GKSTAT_BLKSIZE "sdbc_blksize"
#define SDBC_GKSTAT_LRU_BLOCKS "sdbc_lru_blocks"
#ifdef DEBUG
#define SDBC_GKSTAT_LRU_NOREQ "sdbc_lru_noreq"
#define SDBC_GKSTAT_LRU_REQ "sdbc_lru_req"
#endif
#define SDBC_GKSTAT_WLRU_INQ "sdbc_wlru_inq"
#define SDBC_GKSTAT_CACHESIZE "sdbc_cachesize"
#define SDBC_GKSTAT_NUMBLOCKS "sdbc_numblocks"
#define SDBC_GKSTAT_NUM_SHARED "sdbc_num_shared"
#define SDBC_GKSTAT_WRCANCELNS "sdbc_wrcancelns"
#define SDBC_GKSTAT_DESTAGED "sdbc_destaged"
#define SDBC_GKSTAT_NODEHINTS "sdbc_nodehints"
/* per-cache descriptor kstats field names */
#define SDBC_CDKSTAT_VOL_NAME "sdbc_vol_name"
#define SDBC_CDKSTAT_FAILED "sdbc_failed"
#define SDBC_CDKSTAT_CD "sdbc_cd"
#define SDBC_CDKSTAT_CACHE_READ "sdbc_cache_read"
#define SDBC_CDKSTAT_CACHE_WRITE "sdbc_cache_write"
#define SDBC_CDKSTAT_DISK_READ "sdbc_disk_read"
#define SDBC_CDKSTAT_DISK_WRITE "sdbc_disk_write"
#define SDBC_CDKSTAT_FILESIZE "sdbc_filesize"
#define SDBC_CDKSTAT_NUMDIRTY "sdbc_numdirty"
#define SDBC_CDKSTAT_NUMIO "sdbc_numio"
#define SDBC_CDKSTAT_NUMFAIL "sdbc_numfail"
#define SDBC_CDKSTAT_DESTAGED "sdbc_destaged"
#define SDBC_CDKSTAT_WRCANCELNS "sdbc_wrcancelns"
#define SDBC_CDKSTAT_CDHINTS "sdbc_cdhints"
#ifdef DEBUG
/* dynmem kstats field names */
#define SDBC_DMKSTAT_MONITOR_DYNMEM "sdbc_monitor_dynmem"
#define SDBC_DMKSTAT_MAX_DYN_LIST "sdbc_max_dyn_list"
#define SDBC_DMKSTAT_CACHE_AGING_CT1 "sdbc_cache_aging_ct1"
#define SDBC_DMKSTAT_CACHE_AGING_CT2 "sdbc_cache_aging_ct2"
#define SDBC_DMKSTAT_CACHE_AGING_CT3 "sdbc_cache_aging_ct3"
#define SDBC_DMKSTAT_CACHE_AGING_SEC1 "sdbc_cache_aging_sec1"
#define SDBC_DMKSTAT_CACHE_AGING_SEC2 "sdbc_cache_aging_sec2"
#define SDBC_DMKSTAT_CACHE_AGING_SEC3 "sdbc_cache_aging_sec3"
#define SDBC_DMKSTAT_CACHE_AGING_PCNT1 "sdbc_cache_aging_pcnt1"
#define SDBC_DMKSTAT_CACHE_AGING_PCNT2 "sdbc_cache_aging_pcnt2"
#define SDBC_DMKSTAT_MAX_HOLDS_PCNT "sdbc_max_holds_pcnt"
#define SDBC_DMKSTAT_ALLOC_CNT "sdbc_alloc_cnt"
#define SDBC_DMKSTAT_DEALLOC_CNT "sdbc_dealloc_cnt"
#define SDBC_DMKSTAT_HISTORY "sdbc_history"
#define SDBC_DMKSTAT_NODATAS "sdbc_nodatas"
#define SDBC_DMKSTAT_CANDIDATES "sdbc_candidates"
#define SDBC_DMKSTAT_DEALLOCS "sdbc_deallocs"
#define SDBC_DMKSTAT_HOSTS "sdbc_hosts"
#define SDBC_DMKSTAT_PESTS "sdbc_pests"
#define SDBC_DMKSTAT_METAS "sdbc_metas"
#define SDBC_DMKSTAT_HOLDS "sdbc_holds"
#define SDBC_DMKSTAT_OTHERS "sdbc_others"
#define SDBC_DMKSTAT_NOTAVAIL "sdbc_notavail"
#define SDBC_DMKSTAT_PROCESS_DIRECTIVE "sdbc_process_directive"
#define SDBC_DMKSTAT_SIMPLECT "sdbc_simplect"
#endif
/* ... values are in range [0-BLK_FBAS] */
typedef unsigned char *ucaddr_t; /* unsigned char pointer */
/*
* Atomic exchange function
*/
#ifdef _KERNEL
/*
* Note: ldstub sets all bits in the memory byte.
* so far this is compatible with the usage of xmem_bu() whereby
* the values of ptr are either 0 or 1, and the xmem_bu() is used
* to set the byte to 1.
*/
#define atomic_swap xmem_bu
#define sd_serialize nsc_membar_stld
#endif /* _KERNEL */
#if defined(_SD_8K_BLKSIZE)
typedef unsigned short _sd_bitmap_t;
#else
typedef unsigned char _sd_bitmap_t;
#endif
/*
* CCTL flag types
*/
/*
* Note: CC_INUSE and CC_PAGEIO are dummy flags that are used in
* individual flags bytes (cc_inuse and cc_pageio) NOT cc_flag.
* Thus they can take any convenient value, however, they must be
* distinct and non-zero.
*/
/*
* Real cc_flag values.
*/
/* specify the size of _sd_cctl[] array */
#define _SD_CCTL_GROUPS 32
/*
* Individual SDBC cache block entry
* CC_INUSE bit in cc_flag; special handling of rare collisions.
* "cc_pageio" flusher / client locking of pagelist io operations,
* "cc_iostatus" is set by flusher without holding cc_lock,
* writer will set CC_PEND_DIRTY if cc_iostatus is set.
* Thus "cc_inuse", "cc_iostatus" and "cc_pageio" are volatile.
*
* The cc_await_* values are in the main _sd_cctl to avoid over
* signalling _cc_blkcv.
*
* The _sd_cctl structure is aligned to group related members and
* to ensure good packing.
*/
typedef struct _sd_cctl_sync {
typedef struct sd_addr_s { /* Generic address structure */
unsigned char *sa_virt; /* Virtual address of data */
} sd_addr_t;
/*
* See notes above.
*/
typedef struct _sd_cctl {
volatile int net_iostatus; /* net status of io */
char cc_iocount; /* number of ios in progress */
/* support for backend i/o memory coalescing */
int cc_anon_len; /* length of anon mem */
int cc_hits;
/* dynamic memory support fields */
/* see defines */
int cc_alloc_size_dm; /* mem allocation */
/* size bytes */
/* chain */
/* ptr of all centrys */
/* dynmem chains */
/* _sd_queue_t *cc_dmchain_q; dmqueue */
int cc_cblocks; /* number of centrys for size_dm */
/* debugging stats */
int cc_alloc_ct_dm;
int cc_dealloc_ct_dm;
} _sd_cctl_t;
/* cache entry allocation tokens */
typedef struct sdbc_allocbuf_s {
typedef struct sdbc_allocbuf_impl_s {
int sab_q; /* dmqueue of last chain allocated */
int reserved; /* stats ? */
/*
* bits for flag argument to sdbc_centry_alloc() and callees.
*/
/*
* definitions supporting the dynmem dealloc thread
*/
#define LOW_RESOURCES_DM -1
#define NO_THREAD_DM -1
#define PROCESS_CACHE_DM 0
#define CACHE_SHUTDOWN_DM 1
#define CACHE_THREAD_TERMINATED_DM 2
#define TIME_DELAY_LVL0 3
#define TIME_DELAY_LVL1 4
#define TIME_DELAY_LVL2 5
#define HISTORY_LVL0 (ushort_t)0
/*
* definitions supporing the ddditional fields in the cache
* entry structure for dyn mem
*/
#define FIRST_AGING_DM 0x00000001
#define FINAL_AGING_DM 0x000000ff
/* out of sd_centry_alloc() */
/* out of sd_centry_alloc() */
#define HOST_ENTRY_DM 0x00000400
#define PARASITIC_ENTRY_DM 0x00000800
#define STICKY_METADATA_DM 0x00001000
#define ELIGIBLE_ENTRY_DM 0x00002000
#define HASH_ENTRY_DM 0x00008000
#define HOLD_ENTRY_DM 0x00010000
#define AVAIL_ENTRY_DM 0x00020000
/* info only */
/* error processing */
/*
* definitions supporting the dynmem monitoring
*/
#define RPT_SHUTDOWN_PROCESS_DM 0x00000001
/* other,dealloc */
/*
* definitions supporting the processing directive bit flags
*/
/* on then cleared */
/* on then cleared */
/*
* Default - Max - Min definitions
*/
#define MAX_DYN_LIST_DEFAULT 8
#define MONITOR_DYNMEM_PROCESS_DEFAULT 0
#define CACHE_AGING_CT_DEFAULT 3
#define CACHE_AGING_SEC1_DEFAULT 10
#define CACHE_AGING_SEC2_DEFAULT 5
#define CACHE_AGING_SEC3_DEFAULT 1
#define CACHE_AGING_PCNT1_DEFAULT 50
#define CACHE_AGING_PCNT2_DEFAULT 25
#define MAX_HOLDS_PCNT_DEFAULT 0
#define PROCESS_DIRECTIVE_DEFAULT 0
#define CACHE_AGING_PCNT1_MAX 100
#define CACHE_AGING_PCNT2_MAX 100
#define MAX_HOLDS_PCNT_MAX 100
/*
* dynmem global structure defn
*/
typedef struct _dm_process_vars {
int sd_dealloc_flagx; /* gen'l purpose bit flag */
int monitor_dynmem_process; /* bit flag indicating what to report */
int max_dyn_list; /* max num of pages to allow list to */
/* grow */
/* cache aging parameter set */
int cache_aging_ct1; /* hosts/pests - aging hits which */
/* trigger dealloc */
int cache_aging_ct2; /* metas - aging hits which */
/* trigger dealloc not yet imple */
int cache_aging_ct3; /* holds - aging hits which */
/* trigger dealloc */
int cache_aging_sec1; /* sleep time between cache list */
/* exam - 100% to pcnt1 free */
int cache_aging_sec2; /* sleep time between cache list */
/* exam - pcnt1 to pcnt2 free */
int cache_aging_sec3; /* sleep time between cache list */
/* exam - pcnt2 to 0% free */
int cache_aging_pcnt1; /* % free when to kick in accel */
/* aging - sec2 */
int cache_aging_pcnt2; /* % free when to kick in accel */
/* aging - sec3 */
int max_holds_pcnt; /* max % of cents to act as holdovers */
/* stats - debug */
int alloc_ct; /* gross count */
int dealloc_ct; /* gross count */
/* thread stats - debug and on the fly tuning of dealloc vars */
int history; /* history flag */
int nodatas; /* # cctls w/o data assigned */
int candidates; /* # cand. for dealloc checking */
int deallocs; /* # deallocs */
int hosts; /* # hosts */
int pests; /* # pests */
int metas; /* # metas - sticky meata data */
int holds; /* # holdovers - single page, fully */
/* aged but not dealloc'd or hash */
/* del'd */
int others; /* # everybody else */
int process_directive; /* processing directive bitmap flag */
/* standard stats (no prefetch tallies here) */
int read_hits; /* found in cache memory */
int read_misses; /* not found in cache memory */
int write_hits; /* found in cache memory */
int write_misses; /* not found in cache memory */
int write_thru; /* not bothering to put in cache mem */
/*
* prefetch tracked by _sd_prefetch_valid_cnt and _sd_prefetch_busy_cnt
* might want different usage ?
*/
int prefetch_hits;
int prefetch_misses;
/*
* dynmem interface
*/
/*
* Defines to hide the sd_addr_t structure
*/
/*
* Defines to hide the synchronisation block
*/
/*
* This struct exists solely so that sd_info is able to
* extract this kind of data from sdbc without passing out
* the entire _sd_cctl_t which has lots of pointers which
* makes it impossible to deal with in 32bit program and an
* LP64 kernel.
*/
typedef struct {
int ci_write; /* 0 == no wrt data */
int ci_cd; /* the cd */
} sdbc_info_t;
typedef struct _sd_wr_cctl {
typedef struct _sd_queue {
char sq_await; /* number blocked on lru sema */
int sq_inq; /* Number of LRU entries in q */
unsigned int sq_seq; /* sequence number for lru optim */
unsigned int sq_req_stat;
unsigned int sq_noreq_stat;
/* dmchain support */
int sq_dmchain_cblocks; /* dmchain len in ccents */
} _sd_queue_t;
/*
* The net structure contains which memory net has been configured for
* cache, the amount of space allocated, the write control and fault
* tolerant blocks etc
*/
typedef struct _sd_net {
unsigned short sn_psize; /* Page size of memory in this net */
unsigned char sn_configured; /* is this network configured */
int sn_cpages; /* number of pages for Cache */
#endif /* _KERNEL || _KMEMUSER */
/*
* Shared structure shared between cds and statistics
*
* NOTE - this structure is visible as an ioctl result.
* If anything changes here _sd_get_stats() and convert_stats()
* will need to be changed.
*/
typedef struct _sd_shared {
/* 1 == i/o error, 2 == open failed ) */
unsigned short sh_cd; /* the cache descriptor. (for stats) */
int sh_cache_read; /* Number of FBAs read from cache */
int sh_cache_write; /* Number of FBAs written to cache */
int sh_disk_read; /* Number of FBAs read from disk */
int sh_disk_write; /* Number of FBAs written to disk */
volatile int sh_numdirty; /* Number of dirty blocks */
volatile int sh_numio; /* Number of blocks on way to disk */
volatile int sh_numfail; /* Number of blocks failed */
int sh_flushloop; /* Loops delayed so far */
int sh_flag; /* Flags visible to user programs */
int sh_destaged; /* number of bytes destaged to disk */
int sh_wrcancelns; /* number of writes to dirty blocks */
char sh_filename[NSC_MAXPATH];
} _sd_shared_t;
/*
* Cache descriptor information.
*/
typedef struct _sd_cd_info {
int cd_desc; /* The cache descriptor */
int cd_flag; /* Flag */
unsigned int cd_hint; /* Hints for this descriptor */
int cd_lastchain; /* sequential optimization */
struct _sd_cctl *cd_fail_head;
char cd_failover; /* done nsc_reserve during failover */
volatile char cd_recovering; /* cd is being recovered failover or */
/* disk_online */
char cd_write_inprogress;
struct sd_net_hnd *net_hnd;
typedef struct _sd_buf_hlist {
short hl_count;
#endif /* _KERNEL || _KMEMUSER */
/*
* Index into the following st_mem_sizes[] array
*/
#define _SD_CACHE_MEM 0x01
#define _SD_IOBUF_MEM 0x02
#define _SD_HASH_MEM 0x03
#define _SD_GLOBAL_MEM 0x04
#define _SD_STATS_MEM 0x05
/* maintain stat struct layout */
#define NUM_WQ_PAD 4
/*
* cache statistics structure
*
* NOTE - if anything changes here _sd_get_stats() and convert_stats()
* must be changed and _sd_stats32_t must also be synchronized.
*
*/
typedef struct _sd_stats {
int net_dirty;
int net_pending;
int net_free;
int st_count; /* number of opens for device */
int st_loc_count; /* number of open devices */
int st_rdhits; /* number of read hits */
int st_rdmiss; /* number of read misses */
int st_wrhits; /* number of write hits */
int st_wrmiss; /* number of write misses */
int st_blksize; /* cache block size (in bytes) */
int st_wlru_inq; /* number of write blocks */
int st_cachesize; /* cache size (in bytes) */
int st_numblocks; /* # of cache blocks */
int st_wrcancelns; /* # of write cancellations */
int st_destaged; /* # of bytes destaged to disk */
} _sd_stats_t;
typedef struct _sd_stats_32 {
int net_dirty;
int net_pending;
int net_free;
int st_count; /* number of opens for device */
int st_loc_count; /* number of open devices */
int st_rdhits; /* number of read hits */
int st_rdmiss; /* number of read misses */
int st_wrhits; /* number of write hits */
int st_wrmiss; /* number of write misses */
int st_blksize; /* cache block size (in bytes) */
int st_wlru_inq; /* number of write blocks */
int st_cachesize; /* cache size (in bytes) */
int st_numblocks; /* # of cache blocks */
int st_wrcancelns; /* # of write cancellations */
int st_destaged; /* # of bytes destaged to disk */
/*
* The map structure contains mapping between a mask and relevent information
* that would take some computation at runtime.
* Given a mask, what is the first LSB set (stpos)
* Given a mask, what are the consecutive number of LSB bits set (len)
* Given a mask, what would be a new mask if the consecutive LSB bits are reset
* Given a mask, how many ios would be needed to flush this block.
* Given a mask, how many buffer descriptor lists (bdls) would be needed
* on a read.
*/
typedef struct _sd_map_info {
unsigned char mi_stpos; /* position of first LSB set */
unsigned char mi_len; /* Length of consecutive LSB set */
unsigned char mi_dirty_count; /* number of fragmented bits */
unsigned char mi_io_count; /* number of bdls for a given mask */
/*
* cc_inuse is set with atomic exchange instruction
* when clearing, must check for waiters.
* sd_serialize prohibits speculative reads
*/
#define SET_CENTRY_INUSE(centry) \
#define CLEAR_CENTRY_INUSE(centry) { \
sd_serialize(); \
if ((centry)->cc_await_use) { \
} \
}
/*
* cc_pageio is set with atomic exchange instruction
* when clearing, must check for waiters.
* sd_serialize prohibits speculative reads
*/
#define SET_CENTRY_PAGEIO(centry) \
while (SET_CENTRY_PAGEIO(centry)) { \
(stat)++; \
} \
}
#define CLEAR_CENTRY_PAGEIO(centry) { \
sd_serialize(); \
if ((centry)->cc_await_page) { \
} \
}
#endif /* _KERNEL || _KMEMUSER */
#if defined(_KERNEL)
#define CENTRY_SET_FTPOS(centry) \
#define ASSERT_LEN(len) \
if (len > _SD_MAX_FBAS) {\
"sdbc(ASSERT_LEN) fba exceeds limits. fba_len %" NSC_SZFMT \
return (EIO); }
"sdbc(ASSERT_IO_SIZE) io beyond end of file." \
return (EIO); \
}
"sdbc(ASSERT_HANDLE_LIMITS) operation out of bounds" \
return (EINVAL); \
}
#define _SD_NODE_HINTS (_sd_node_hint)
if (cd == _CD_NOHASH) \
else \
_SD_NODE_HINTS | NSC_HACTIVE); \
}
& CD_ALLOCATED))
/*
* bitmap stuff
*/
#endif /* _KERNEL */
#define SET_FULLY_VALID(cc_entry) \
#endif /* _KERNEL || _KMEMUSER */
#if defined(_KERNEL)
#if !defined(_SD_NOSTATS)
#define CACHE_WRITE_CANCELLATION(cd) {\
if ((cd) < sdbc_max_devs)\
}
}
}\
if (sdbc_global_io_kstat) {\
}\
}
}\
if (sdbc_global_io_kstat) {\
}\
}
/* start timer measuring amount of time spent in the cache */
#define KSTAT_RUNQ_ENTER(cd) {\
}\
if (sdbc_global_io_kstat) {\
}\
}
/* stop timer measuring amount of time spent in the cache */
#define KSTAT_RUNQ_EXIT(cd) {\
}\
if (sdbc_global_io_kstat) {\
}\
}
#else
#define CACHE_READ_HIT
#define CACHE_READ_MISS
#define CACHE_WRITE_HIT
#define CACHE_WRITE_MISS
#define CACHE_WRITE_CANCELLATION(cd)
#endif
#endif /* _KERNEL */
/* defines for sh_alloc */
#define CD_ALLOC_IN_PROGRESS 0x0001
#define CD_ALLOCATED 0x0002
#define CD_CLOSE_IN_PROGRESS 0x0010
/* defines for sh_flag */
#define CD_ATTACHED 0x0001
#ifdef _KERNEL
#define _SD_DISCONNECT_CALLBACK(hndl) \
if ((hndl)->bh_disconnect_cb) { \
}
#define _SD_READ_CALLBACK(hndl) \
if ((hndl)->bh_read_cb) \
"sdbc(_SD_READ_CALLBACK) not registered. io lost");
#define _SD_WRITE_CALLBACK(hndl) \
if ((hndl)->bh_write_cb) \
"sdbc(_SD_WRITE_CALLBACK) not registered. io lost");
#endif /* _KERNEL */
#if defined(_SD_LRU_OPTIMIZE)
/*
* Do not requeue if we fall into the tail 25% of the lru
*/
#define _sd_lru_reinsert(q, ent) \
1 : ((q->sq_noreq_stat)++, 0))
#else
#endif
#if defined(_KERNEL)
#define SD_WR_NUMIO 100
/*
* These defines are the hardwired values after sd_config_param was
* zapped. Ought to remove the use of these entirely ....
*/
SD_WR_NUMIO) ? \
/* -------------------------------- END sd_config_param defines ---------- */
/*
* ncall usage
*/
#define SD_ENABLE (NCALL_SDBC + 0)
#ifdef lint
#define LINTUSED(x) (void)(x)++
#else
#define LINTUSED(x)
#endif
extern int BLK_FBAS;
extern _sd_bitmap_t BLK_FBA_BITS;
extern _sd_bitmap_t _fba_bits[];
extern _sd_cctl_t *_sd_cctl[];
extern _sd_cd_info_t *_sd_cache_files;
extern _sd_hash_table_t *_sd_htable;
extern _sd_map_info_t _sd_lookup_map[];
extern _sd_net_t _sd_net_config;
extern _sd_queue_t _sd_lru_q;
extern _sd_stats_t *_sd_cache_stats;
extern char _sd_contig_bmap[];
extern int CACHE_BLOCK_SIZE;
extern int CBLOCKS;
extern int _sd_cctl_groupsz;
extern int sdbc_static_cache;
extern kmutex_t _sd_cache_lock;
extern nsc_def_t _sd_sdbc_def[];
extern uint_t _sd_node_hint;
extern int _sd_minidsp;
extern krwlock_t sdbc_queue_lock;
extern safestore_ops_t *sdbc_safestore;
extern ss_common_config_t safestore_config;
extern ss_voldata_t *_sdbc_gl_file_info;
extern void _sdbc_cache_deconfigure(void);
extern int _sdbc_remote_store_pinned(int cd);
extern _sd_cctl_t *_sd_centry_alloc(int, int, int *, int, int);
extern int _sd_centry_setup_dm(_sd_cctl_t *, int, int);
extern void _sdbc_dealloc_deconfigure_dm(void);
extern int _sdbc_dealloc_configure_dm(void);
int numq);
extern void _sdbc_handles_unload(void);
extern int _sdbc_handles_load(void);
extern int _sdbc_handles_configure();
extern void _sdbc_handles_deconfigure(void);
extern void _sd_init_contig_bmap(void);
extern void _sd_init_lookup_map(void);
extern int sd_get_file_info_size(void *uaddrp);
extern int sd_get_file_info_data(char *uaddrp);
extern int sd_get_glmul_sizes(int *uaddrp);
extern int sd_get_glmul_info(char *uaddrp);
sdbc_allocbuf_t *, int);
extern int _sdbc_ft_hold_io;
extern kcondvar_t _sdbc_ft_hold_io_cv;
extern kmutex_t _sdbc_ft_hold_io_lk;
#ifdef DEBUG
/* for testing only */
extern int _sdbc_flush_flag; /* inhibit flush for testing */
extern int _sdbc_clear_ioerr(int);
extern int _sdbc_inject_ioerr(int, int, int);
extern void _sdbc_ioj_set_dev(int, dev_t);
extern void _sdbc_ioj_load();
extern void _sdbc_ioj_unload();
#endif
#endif /* _KERNEL */
#ifdef __cplusplus
}
#endif
#endif /* _SD_BCACHE_H */