17836SJohn.Forte@Sun.COM /*
27836SJohn.Forte@Sun.COM * CDDL HEADER START
37836SJohn.Forte@Sun.COM *
47836SJohn.Forte@Sun.COM * The contents of this file are subject to the terms of the
57836SJohn.Forte@Sun.COM * Common Development and Distribution License (the "License").
67836SJohn.Forte@Sun.COM * You may not use this file except in compliance with the License.
77836SJohn.Forte@Sun.COM *
87836SJohn.Forte@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97836SJohn.Forte@Sun.COM * or http://www.opensolaris.org/os/licensing.
107836SJohn.Forte@Sun.COM * See the License for the specific language governing permissions
117836SJohn.Forte@Sun.COM * and limitations under the License.
127836SJohn.Forte@Sun.COM *
137836SJohn.Forte@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
147836SJohn.Forte@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157836SJohn.Forte@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
167836SJohn.Forte@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
177836SJohn.Forte@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
187836SJohn.Forte@Sun.COM *
197836SJohn.Forte@Sun.COM * CDDL HEADER END
207836SJohn.Forte@Sun.COM */
217836SJohn.Forte@Sun.COM /*
22*9093SRamana.Srikanth@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
237836SJohn.Forte@Sun.COM * Use is subject to license terms.
247836SJohn.Forte@Sun.COM */
257836SJohn.Forte@Sun.COM
267836SJohn.Forte@Sun.COM #include <sys/types.h>
277836SJohn.Forte@Sun.COM #include <sys/ksynch.h>
287836SJohn.Forte@Sun.COM #include <sys/kmem.h>
297836SJohn.Forte@Sun.COM #include <sys/errno.h>
307836SJohn.Forte@Sun.COM #include <sys/cmn_err.h>
317836SJohn.Forte@Sun.COM #include <sys/debug.h>
327836SJohn.Forte@Sun.COM #include <sys/cred.h>
337836SJohn.Forte@Sun.COM #include <sys/file.h>
347836SJohn.Forte@Sun.COM #include <sys/ddi.h>
357836SJohn.Forte@Sun.COM #include <sys/nsctl/nsctl.h>
367836SJohn.Forte@Sun.COM #include <sys/unistat/spcs_s.h>
377836SJohn.Forte@Sun.COM #include <sys/unistat/spcs_errors.h>
387836SJohn.Forte@Sun.COM
397836SJohn.Forte@Sun.COM #include <sys/unistat/spcs_s_k.h>
407836SJohn.Forte@Sun.COM #include "dsw.h"
417836SJohn.Forte@Sun.COM #include "dsw_dev.h"
427836SJohn.Forte@Sun.COM
437836SJohn.Forte@Sun.COM #ifdef DS_DDICT
447836SJohn.Forte@Sun.COM #include "../contract.h"
457836SJohn.Forte@Sun.COM #endif
467836SJohn.Forte@Sun.COM
477836SJohn.Forte@Sun.COM #include <sys/sdt.h> /* dtrace is S10 or later */
487836SJohn.Forte@Sun.COM
497836SJohn.Forte@Sun.COM /*
507836SJohn.Forte@Sun.COM * Instant Image.
517836SJohn.Forte@Sun.COM *
527836SJohn.Forte@Sun.COM * This file contains the chunk map lookup functions of II.
537836SJohn.Forte@Sun.COM *
547836SJohn.Forte@Sun.COM */
557836SJohn.Forte@Sun.COM #define CHUNK_FBA(chunk) DSW_CHK2FBA(chunk)
567836SJohn.Forte@Sun.COM
577836SJohn.Forte@Sun.COM extern int ii_debug; /* debug level switch */
587836SJohn.Forte@Sun.COM int ii_map_debug = 0;
597836SJohn.Forte@Sun.COM
607836SJohn.Forte@Sun.COM #ifdef II_MULTIMULTI_TERABYTE
617836SJohn.Forte@Sun.COM typedef int64_t nodeid_t;
627836SJohn.Forte@Sun.COM typedef int32_t nodeid32_t;
637836SJohn.Forte@Sun.COM #else
647836SJohn.Forte@Sun.COM typedef int32_t nodeid_t;
657836SJohn.Forte@Sun.COM #endif
667836SJohn.Forte@Sun.COM
677836SJohn.Forte@Sun.COM typedef struct ii_node {
687836SJohn.Forte@Sun.COM chunkid_t vchunk_id; /* virtual chunk id */
697836SJohn.Forte@Sun.COM } NODE;
707836SJohn.Forte@Sun.COM
717836SJohn.Forte@Sun.COM typedef struct ii_nodelink_s {
727836SJohn.Forte@Sun.COM chunkid_t next_chunk;
737836SJohn.Forte@Sun.COM } ii_nodelink_t;
747836SJohn.Forte@Sun.COM
757836SJohn.Forte@Sun.COM static int nodes_per_fba = FBA_SIZE(1) / sizeof (NODE);
767836SJohn.Forte@Sun.COM
777836SJohn.Forte@Sun.COM ii_header_t *_ii_bm_header_get(_ii_info_t *ip, nsc_buf_t **tmp);
787836SJohn.Forte@Sun.COM int _ii_bm_header_put(ii_header_t *hdr, _ii_info_t *ip,
797836SJohn.Forte@Sun.COM nsc_buf_t *tmp);
807836SJohn.Forte@Sun.COM void _ii_rlse_devs(_ii_info_t *, int);
817836SJohn.Forte@Sun.COM int _ii_rsrv_devs(_ii_info_t *, int, int);
827836SJohn.Forte@Sun.COM void _ii_error(_ii_info_t *, int);
837836SJohn.Forte@Sun.COM /*
847836SJohn.Forte@Sun.COM * Private functions for use in this file.
857836SJohn.Forte@Sun.COM */
867836SJohn.Forte@Sun.COM static void free_node(_ii_info_t *ip, NODE *np, nodeid_t ni);
877836SJohn.Forte@Sun.COM static chunkid_t ii_alloc_overflow(_ii_info_t *ip);
887836SJohn.Forte@Sun.COM void ii_free_overflow(_ii_info_t *, chunkid_t);
897836SJohn.Forte@Sun.COM extern int _ii_nsc_io(_ii_info_t *, int, nsc_fd_t *, int, nsc_off_t,
907836SJohn.Forte@Sun.COM unsigned char *, nsc_size_t);
917836SJohn.Forte@Sun.COM
927836SJohn.Forte@Sun.COM static int
update_tree_header(_ii_info_t * ip)937836SJohn.Forte@Sun.COM update_tree_header(_ii_info_t *ip)
947836SJohn.Forte@Sun.COM {
957836SJohn.Forte@Sun.COM ii_header_t *header;
967836SJohn.Forte@Sun.COM nsc_buf_t *tmp = NULL;
977836SJohn.Forte@Sun.COM
987836SJohn.Forte@Sun.COM mutex_enter(&ip->bi_mutex);
997836SJohn.Forte@Sun.COM header = _ii_bm_header_get(ip, &tmp);
1007836SJohn.Forte@Sun.COM if (header == NULL) {
1017836SJohn.Forte@Sun.COM /* bitmap is probably offline */
1027836SJohn.Forte@Sun.COM mutex_exit(&ip->bi_mutex);
1037836SJohn.Forte@Sun.COM DTRACE_PROBE(_iit_update_tree_header_end);
1047836SJohn.Forte@Sun.COM return (1);
1057836SJohn.Forte@Sun.COM }
1067836SJohn.Forte@Sun.COM header->ii_mstchks = ip->bi_mstchks;
1077836SJohn.Forte@Sun.COM header->ii_shdchks = ip->bi_shdchks;
1087836SJohn.Forte@Sun.COM header->ii_shdchkused = ip->bi_shdchkused;
1097836SJohn.Forte@Sun.COM header->ii_shdfchk = ip->bi_shdfchk;
1107836SJohn.Forte@Sun.COM (void) _ii_bm_header_put(header, ip, tmp);
1117836SJohn.Forte@Sun.COM mutex_exit(&ip->bi_mutex);
1127836SJohn.Forte@Sun.COM
1137836SJohn.Forte@Sun.COM return (0);
1147836SJohn.Forte@Sun.COM }
1157836SJohn.Forte@Sun.COM
1167836SJohn.Forte@Sun.COM static int
update_overflow_header(_ii_info_t * ip,_ii_overflow_t * op)1177836SJohn.Forte@Sun.COM update_overflow_header(_ii_info_t *ip, _ii_overflow_t *op)
1187836SJohn.Forte@Sun.COM {
1197836SJohn.Forte@Sun.COM (void) _ii_nsc_io(ip, KS_OVR, op->ii_dev->bi_fd, NSC_WRBUF,
1207836SJohn.Forte@Sun.COM II_OHEADER_FBA, (unsigned char *)&(op->ii_do),
1217836SJohn.Forte@Sun.COM sizeof (_ii_doverflow_t));
1227836SJohn.Forte@Sun.COM
1237836SJohn.Forte@Sun.COM return (0);
1247836SJohn.Forte@Sun.COM }
1257836SJohn.Forte@Sun.COM
1267836SJohn.Forte@Sun.COM static int
node_io(_ii_info_t * ip,NODE * np,nodeid_t node,int flag)1277836SJohn.Forte@Sun.COM node_io(_ii_info_t *ip, NODE *np, nodeid_t node, int flag)
1287836SJohn.Forte@Sun.COM {
1297836SJohn.Forte@Sun.COM int rc;
1307836SJohn.Forte@Sun.COM int node_fba;
1317836SJohn.Forte@Sun.COM int tree_fba = ip->bi_copyfba + (ip->bi_copyfba-ip->bi_shdfba);
1327836SJohn.Forte@Sun.COM int offset;
1337836SJohn.Forte@Sun.COM nsc_buf_t *tmp = NULL;
1347836SJohn.Forte@Sun.COM
1357836SJohn.Forte@Sun.COM /*
1367836SJohn.Forte@Sun.COM * Don't use _ii_nsc_io() as _ii_nsc_io() requires io to start at
1377836SJohn.Forte@Sun.COM * an fba boundary.
1387836SJohn.Forte@Sun.COM */
1397836SJohn.Forte@Sun.COM
1407836SJohn.Forte@Sun.COM /* calculate location of node on bitmap file */
1417836SJohn.Forte@Sun.COM offset = (node % nodes_per_fba) * sizeof (NODE);
1427836SJohn.Forte@Sun.COM node_fba = tree_fba + node / nodes_per_fba;
1437836SJohn.Forte@Sun.COM
1447836SJohn.Forte@Sun.COM /* read disk block containing node */
1457836SJohn.Forte@Sun.COM rc = nsc_alloc_buf(ip->bi_bmpfd, node_fba, 1, NSC_RDBUF|flag, &tmp);
1467836SJohn.Forte@Sun.COM if (!II_SUCCESS(rc)) {
1477836SJohn.Forte@Sun.COM _ii_error(ip, DSW_BMPOFFLINE);
1487836SJohn.Forte@Sun.COM if (tmp)
1497836SJohn.Forte@Sun.COM (void) nsc_free_buf(tmp);
1507836SJohn.Forte@Sun.COM
1517836SJohn.Forte@Sun.COM DTRACE_PROBE(_iit_node_io_end);
1527836SJohn.Forte@Sun.COM return (1);
1537836SJohn.Forte@Sun.COM }
1547836SJohn.Forte@Sun.COM
1557836SJohn.Forte@Sun.COM /* copy node and update bitmap file if needed */
1567836SJohn.Forte@Sun.COM rc = 0;
1577836SJohn.Forte@Sun.COM if (flag == NSC_RDBUF)
1587836SJohn.Forte@Sun.COM bcopy(tmp->sb_vec->sv_addr+offset, np, sizeof (NODE));
1597836SJohn.Forte@Sun.COM else {
1607836SJohn.Forte@Sun.COM bcopy(np, tmp->sb_vec->sv_addr+offset, sizeof (NODE));
1617836SJohn.Forte@Sun.COM II_NSC_WRITE(ip, bitmap, rc, tmp, node_fba, 1, 0);
1627836SJohn.Forte@Sun.COM if (!II_SUCCESS(rc)) {
1637836SJohn.Forte@Sun.COM _ii_error(ip, DSW_BMPOFFLINE);
1647836SJohn.Forte@Sun.COM rc = EIO;
1657836SJohn.Forte@Sun.COM }
1667836SJohn.Forte@Sun.COM }
1677836SJohn.Forte@Sun.COM if (tmp)
1687836SJohn.Forte@Sun.COM (void) nsc_free_buf(tmp);
1697836SJohn.Forte@Sun.COM
1707836SJohn.Forte@Sun.COM return (0);
1717836SJohn.Forte@Sun.COM }
1727836SJohn.Forte@Sun.COM
1737836SJohn.Forte@Sun.COM static int
node_fba_fill(_ii_info_t * ip,nsc_size_t nchunks,chunkid_t vchunk_id)1747836SJohn.Forte@Sun.COM node_fba_fill(_ii_info_t *ip, nsc_size_t nchunks, chunkid_t vchunk_id)
1757836SJohn.Forte@Sun.COM {
1767836SJohn.Forte@Sun.COM int rc;
1777836SJohn.Forte@Sun.COM nsc_off_t fba;
1787836SJohn.Forte@Sun.COM nsc_size_t fbas;
1797836SJohn.Forte@Sun.COM nsc_size_t maxfbas;
1807836SJohn.Forte@Sun.COM nsc_buf_t *bp;
1817836SJohn.Forte@Sun.COM nsc_vec_t *vp;
1827836SJohn.Forte@Sun.COM
1837836SJohn.Forte@Sun.COM /* Determine maximum number of FBAs to allocate */
1847836SJohn.Forte@Sun.COM rc = nsc_maxfbas(ip->bi_bmpfd, 0, &maxfbas);
1857836SJohn.Forte@Sun.COM if (!II_SUCCESS(rc))
1867836SJohn.Forte@Sun.COM maxfbas = DSW_CBLK_FBA;
1877836SJohn.Forte@Sun.COM
1887836SJohn.Forte@Sun.COM /* Write out blocks of initialied NODEs */
1897836SJohn.Forte@Sun.COM fba = ip->bi_copyfba + (ip->bi_copyfba-ip->bi_shdfba);
1907836SJohn.Forte@Sun.COM fbas = FBA_LEN(nchunks * sizeof (NODE));
1917836SJohn.Forte@Sun.COM while (fbas > 0) {
1927836SJohn.Forte@Sun.COM
1937836SJohn.Forte@Sun.COM /* Determine number of FBA to allocate this time */
1947836SJohn.Forte@Sun.COM if (fbas < maxfbas) maxfbas = fbas;
1957836SJohn.Forte@Sun.COM
1967836SJohn.Forte@Sun.COM /* Allocate buffer which map to FBAs containing NODEs */
1977836SJohn.Forte@Sun.COM bp = NULL;
1987836SJohn.Forte@Sun.COM rc = nsc_alloc_buf(ip->bi_bmpfd, fba, maxfbas, NSC_WRBUF, &bp);
1997836SJohn.Forte@Sun.COM if (!II_SUCCESS(rc)) {
2007836SJohn.Forte@Sun.COM _ii_error(ip, DSW_BMPOFFLINE);
2017836SJohn.Forte@Sun.COM DTRACE_PROBE(alloc_buf_failed);
2027836SJohn.Forte@Sun.COM return (EIO);
2037836SJohn.Forte@Sun.COM }
2047836SJohn.Forte@Sun.COM
2057836SJohn.Forte@Sun.COM /* traverse vector list, filling wth initialized NODEs */
2067836SJohn.Forte@Sun.COM for (vp = bp->sb_vec; vp->sv_addr && vp->sv_len; vp++) {
2077836SJohn.Forte@Sun.COM NODE *pnode = (NODE *)vp->sv_addr;
2087836SJohn.Forte@Sun.COM NODE *enode = (NODE *)(vp->sv_addr + vp->sv_len);
2097836SJohn.Forte@Sun.COM while (pnode < enode) {
2107836SJohn.Forte@Sun.COM pnode->vchunk_id = vchunk_id;
2117836SJohn.Forte@Sun.COM pnode++;
2127836SJohn.Forte@Sun.COM }
2137836SJohn.Forte@Sun.COM }
2147836SJohn.Forte@Sun.COM
2157836SJohn.Forte@Sun.COM /* write FBAs containing initialized NODEs */
2167836SJohn.Forte@Sun.COM II_NSC_WRITE(ip, bitmap, rc, bp, fba, maxfbas, 0);
2177836SJohn.Forte@Sun.COM if (!II_SUCCESS(rc)) {
2187836SJohn.Forte@Sun.COM _ii_error(ip, DSW_BMPOFFLINE);
2197836SJohn.Forte@Sun.COM (void) nsc_free_buf(bp);
2207836SJohn.Forte@Sun.COM DTRACE_PROBE(write_failed);
2217836SJohn.Forte@Sun.COM return (EIO);
2227836SJohn.Forte@Sun.COM }
2237836SJohn.Forte@Sun.COM
2247836SJohn.Forte@Sun.COM /* free the buffer */
2257836SJohn.Forte@Sun.COM (void) nsc_free_buf(bp);
2267836SJohn.Forte@Sun.COM
2277836SJohn.Forte@Sun.COM /* Adjust nsc buffer values */
2287836SJohn.Forte@Sun.COM fba += maxfbas;
2297836SJohn.Forte@Sun.COM fbas -= maxfbas;
2307836SJohn.Forte@Sun.COM }
2317836SJohn.Forte@Sun.COM
2327836SJohn.Forte@Sun.COM return (0);
2337836SJohn.Forte@Sun.COM }
2347836SJohn.Forte@Sun.COM
2357836SJohn.Forte@Sun.COM /*
2367836SJohn.Forte@Sun.COM * Reads the node into core and returns a pointer to it.
2377836SJohn.Forte@Sun.COM */
2387836SJohn.Forte@Sun.COM
2397836SJohn.Forte@Sun.COM static NODE *
read_node(_ii_info_t * ip,nodeid_t node)2407836SJohn.Forte@Sun.COM read_node(_ii_info_t *ip, nodeid_t node)
2417836SJohn.Forte@Sun.COM {
2427836SJohn.Forte@Sun.COM NODE *new;
2437836SJohn.Forte@Sun.COM
2447836SJohn.Forte@Sun.COM new = (NODE *)kmem_alloc(sizeof (NODE), KM_SLEEP);
2457836SJohn.Forte@Sun.COM
2467836SJohn.Forte@Sun.COM if (node_io(ip, new, node, NSC_RDBUF)) {
2477836SJohn.Forte@Sun.COM kmem_free(new, sizeof (NODE));
2487836SJohn.Forte@Sun.COM new = NULL;
2497836SJohn.Forte@Sun.COM }
2507836SJohn.Forte@Sun.COM
2517836SJohn.Forte@Sun.COM return (new);
2527836SJohn.Forte@Sun.COM }
2537836SJohn.Forte@Sun.COM
2547836SJohn.Forte@Sun.COM
2557836SJohn.Forte@Sun.COM static chunkid_t
alloc_chunk(_ii_info_t * ip)2567836SJohn.Forte@Sun.COM alloc_chunk(_ii_info_t *ip)
2577836SJohn.Forte@Sun.COM {
2587836SJohn.Forte@Sun.COM ii_nodelink_t nl;
2597836SJohn.Forte@Sun.COM int fba;
2607836SJohn.Forte@Sun.COM chunkid_t rc = II_NULLCHUNK;
2617836SJohn.Forte@Sun.COM
2627836SJohn.Forte@Sun.COM mutex_enter(&ip->bi_chksmutex);
2637836SJohn.Forte@Sun.COM if (ip->bi_shdchkused < ip->bi_shdchks) {
2647836SJohn.Forte@Sun.COM rc = ip->bi_shdchkused++;
2657836SJohn.Forte@Sun.COM } else if (ip->bi_shdfchk != II_NULLCHUNK) {
2667836SJohn.Forte@Sun.COM ASSERT(ip->bi_shdfchk >= 0 && ip->bi_shdfchk < ip->bi_shdchks);
2677836SJohn.Forte@Sun.COM rc = ip->bi_shdfchk;
2687836SJohn.Forte@Sun.COM fba = CHUNK_FBA(rc);
2697836SJohn.Forte@Sun.COM (void) _ii_rsrv_devs(ip, SHDR, II_INTERNAL);
2707836SJohn.Forte@Sun.COM (void) _ii_nsc_io(ip, KS_SHD, SHDFD(ip), NSC_RDBUF, fba,
2717836SJohn.Forte@Sun.COM (unsigned char *)&nl, sizeof (nl));
2727836SJohn.Forte@Sun.COM _ii_rlse_devs(ip, SHDR);
2737836SJohn.Forte@Sun.COM ip->bi_shdfchk = nl.next_chunk;
2747836SJohn.Forte@Sun.COM ASSERT(ip->bi_shdfchk == II_NULLCHUNK ||
2757836SJohn.Forte@Sun.COM (ip->bi_shdfchk >= 0 && ip->bi_shdfchk < ip->bi_shdchks));
2767836SJohn.Forte@Sun.COM } else {
2777836SJohn.Forte@Sun.COM
2787836SJohn.Forte@Sun.COM /* into overflow */
2797836SJohn.Forte@Sun.COM rc = ii_alloc_overflow(ip);
2807836SJohn.Forte@Sun.COM }
2817836SJohn.Forte@Sun.COM mutex_exit(&ip->bi_chksmutex);
2827836SJohn.Forte@Sun.COM (void) update_tree_header(ip);
2837836SJohn.Forte@Sun.COM
2847836SJohn.Forte@Sun.COM return (rc);
2857836SJohn.Forte@Sun.COM }
2867836SJohn.Forte@Sun.COM
2877836SJohn.Forte@Sun.COM /*
2887836SJohn.Forte@Sun.COM * releases memory for node
2897836SJohn.Forte@Sun.COM */
2907836SJohn.Forte@Sun.COM static void /*ARGSUSED*/
release_node(_ii_info_t * ip,NODE * np,nodeid_t ni)2917836SJohn.Forte@Sun.COM release_node(_ii_info_t *ip, NODE *np, nodeid_t ni)
2927836SJohn.Forte@Sun.COM {
2937836SJohn.Forte@Sun.COM kmem_free(np, sizeof (NODE));
2947836SJohn.Forte@Sun.COM
2957836SJohn.Forte@Sun.COM }
2967836SJohn.Forte@Sun.COM
2977836SJohn.Forte@Sun.COM static void
write_node(_ii_info_t * ip,NODE * np,nodeid_t ni)2987836SJohn.Forte@Sun.COM write_node(_ii_info_t *ip, NODE *np, nodeid_t ni)
2997836SJohn.Forte@Sun.COM {
3007836SJohn.Forte@Sun.COM (void) node_io(ip, np, ni, NSC_WRBUF);
3017836SJohn.Forte@Sun.COM release_node(ip, np, ni);
3027836SJohn.Forte@Sun.COM
3037836SJohn.Forte@Sun.COM }
3047836SJohn.Forte@Sun.COM
3057836SJohn.Forte@Sun.COM static void
free_node(_ii_info_t * ip,NODE * np,nodeid_t ni)3067836SJohn.Forte@Sun.COM free_node(_ii_info_t *ip, NODE *np, nodeid_t ni)
3077836SJohn.Forte@Sun.COM {
3087836SJohn.Forte@Sun.COM ii_nodelink_t nl;
3097836SJohn.Forte@Sun.COM int fba;
3107836SJohn.Forte@Sun.COM
3117836SJohn.Forte@Sun.COM if (np == NULL) {
3127836SJohn.Forte@Sun.COM DTRACE_PROBE(_iit_free_node_end);
3137836SJohn.Forte@Sun.COM return;
3147836SJohn.Forte@Sun.COM }
3157836SJohn.Forte@Sun.COM
3167836SJohn.Forte@Sun.COM mutex_enter(&ip->bi_chksmutex);
3177836SJohn.Forte@Sun.COM if (II_ISOVERFLOW(np->vchunk_id)) {
3187836SJohn.Forte@Sun.COM /* link chunk onto overflow free list */
3197836SJohn.Forte@Sun.COM ii_free_overflow(ip, np->vchunk_id);
3207836SJohn.Forte@Sun.COM } else {
3217836SJohn.Forte@Sun.COM /* write old free list head into chunk */
3227836SJohn.Forte@Sun.COM nl.next_chunk = ip->bi_shdfchk;
3237836SJohn.Forte@Sun.COM ip->bi_shdfchk = np->vchunk_id;
3247836SJohn.Forte@Sun.COM ASSERT(ip->bi_shdfchk == II_NULLCHUNK ||
3257836SJohn.Forte@Sun.COM (ip->bi_shdfchk >= 0 && ip->bi_shdfchk < ip->bi_shdchks));
3267836SJohn.Forte@Sun.COM fba = CHUNK_FBA(np->vchunk_id);
3277836SJohn.Forte@Sun.COM (void) _ii_rsrv_devs(ip, SHDR, II_INTERNAL);
3287836SJohn.Forte@Sun.COM (void) _ii_nsc_io(ip, KS_SHD, SHDFD(ip), NSC_WRBUF, fba,
3297836SJohn.Forte@Sun.COM (unsigned char *)&nl, sizeof (nl));
3307836SJohn.Forte@Sun.COM _ii_rlse_devs(ip, SHDR);
3317836SJohn.Forte@Sun.COM /* update free counts */
3327836SJohn.Forte@Sun.COM /* ip->bi_unused++; */
3337836SJohn.Forte@Sun.COM }
3347836SJohn.Forte@Sun.COM np->vchunk_id = II_NULLCHUNK;
3357836SJohn.Forte@Sun.COM (void) node_io(ip, np, ni, NSC_WRBUF);
3367836SJohn.Forte@Sun.COM (void) update_tree_header(ip);
3377836SJohn.Forte@Sun.COM mutex_exit(&ip->bi_chksmutex);
3387836SJohn.Forte@Sun.COM
3397836SJohn.Forte@Sun.COM }
3407836SJohn.Forte@Sun.COM
3417836SJohn.Forte@Sun.COM /*
3427836SJohn.Forte@Sun.COM * Public functions for dsw_dev to use.
3437836SJohn.Forte@Sun.COM */
3447836SJohn.Forte@Sun.COM
3457836SJohn.Forte@Sun.COM /*
3467836SJohn.Forte@Sun.COM * Overflow volume functions.
3477836SJohn.Forte@Sun.COM */
3487836SJohn.Forte@Sun.COM
3497836SJohn.Forte@Sun.COM /* put overflow chunk on the overflow volume free list */
3507836SJohn.Forte@Sun.COM void
ii_free_overflow(_ii_info_t * ip,chunkid_t chunk)3517836SJohn.Forte@Sun.COM ii_free_overflow(_ii_info_t *ip, chunkid_t chunk)
3527836SJohn.Forte@Sun.COM {
3537836SJohn.Forte@Sun.COM ii_nodelink_t nl;
3547836SJohn.Forte@Sun.COM _ii_overflow_t *op;
3557836SJohn.Forte@Sun.COM int fba;
3567836SJohn.Forte@Sun.COM
3577836SJohn.Forte@Sun.COM if (!II_ISOVERFLOW(chunk)) {
3587836SJohn.Forte@Sun.COM DTRACE_PROBE(_iit_free_overflow_end_1);
3597836SJohn.Forte@Sun.COM return;
3607836SJohn.Forte@Sun.COM }
3617836SJohn.Forte@Sun.COM chunk = II_2OVERFLOW(chunk);
3627836SJohn.Forte@Sun.COM
3637836SJohn.Forte@Sun.COM op = ip->bi_overflow;
3647836SJohn.Forte@Sun.COM if (op == NULL) {
3657836SJohn.Forte@Sun.COM #ifdef DEBUG
3667836SJohn.Forte@Sun.COM cmn_err(CE_PANIC, "overflow used, but not attached ip %p",
3677836SJohn.Forte@Sun.COM (void *) ip);
3687836SJohn.Forte@Sun.COM #endif
3697836SJohn.Forte@Sun.COM DTRACE_PROBE(_iit_free_overflow_end_2);
3707836SJohn.Forte@Sun.COM return;
3717836SJohn.Forte@Sun.COM }
3727836SJohn.Forte@Sun.COM mutex_enter(&(op->ii_mutex));
3737836SJohn.Forte@Sun.COM
3747836SJohn.Forte@Sun.COM DTRACE_PROBE(_iit_free_overflow);
3757836SJohn.Forte@Sun.COM
3767836SJohn.Forte@Sun.COM /* write old free list head into chunk */
3777836SJohn.Forte@Sun.COM nl.next_chunk = op->ii_freehead;
3787836SJohn.Forte@Sun.COM fba = CHUNK_FBA(chunk);
3797836SJohn.Forte@Sun.COM (void) nsc_reserve(op->ii_dev->bi_fd, NSC_MULTI);
3807836SJohn.Forte@Sun.COM (void) _ii_nsc_io(ip, KS_OVR, op->ii_dev->bi_fd, NSC_WRBUF, fba,
3817836SJohn.Forte@Sun.COM (unsigned char *)&nl, sizeof (nl));
3827836SJohn.Forte@Sun.COM /* update free counts */
3837836SJohn.Forte@Sun.COM op->ii_unused++;
3847836SJohn.Forte@Sun.COM ASSERT(op->ii_used > 0); /* always use 1 for header */
3857836SJohn.Forte@Sun.COM
3867836SJohn.Forte@Sun.COM /* write chunk id into header freelist start */
3877836SJohn.Forte@Sun.COM op->ii_freehead = chunk;
3887836SJohn.Forte@Sun.COM
3897836SJohn.Forte@Sun.COM (void) update_overflow_header(ip, op);
3907836SJohn.Forte@Sun.COM nsc_release(op->ii_dev->bi_fd);
3917836SJohn.Forte@Sun.COM mutex_exit(&(op->ii_mutex));
3927836SJohn.Forte@Sun.COM
3937836SJohn.Forte@Sun.COM }
3947836SJohn.Forte@Sun.COM
3957836SJohn.Forte@Sun.COM /* reclaim any overflow storage used by the volume */
3967836SJohn.Forte@Sun.COM void
ii_reclaim_overflow(_ii_info_t * ip)3977836SJohn.Forte@Sun.COM ii_reclaim_overflow(_ii_info_t *ip)
3987836SJohn.Forte@Sun.COM {
3997836SJohn.Forte@Sun.COM NODE *node;
4007836SJohn.Forte@Sun.COM nodeid_t node_id;
4017836SJohn.Forte@Sun.COM _ii_overflow_t *op;
4027836SJohn.Forte@Sun.COM
4037836SJohn.Forte@Sun.COM if ((ip->bi_flags & (DSW_VOVERFLOW | DSW_FRECLAIM)) == 0) {
4047836SJohn.Forte@Sun.COM DTRACE_PROBE(_iit_reclaim_overflow_end);
4057836SJohn.Forte@Sun.COM return;
4067836SJohn.Forte@Sun.COM }
4077836SJohn.Forte@Sun.COM
4087836SJohn.Forte@Sun.COM /*
4097836SJohn.Forte@Sun.COM * Determine whether overflow should be reclaimed:
4107836SJohn.Forte@Sun.COM * 1/ If we're not doing a group volume update
4117836SJohn.Forte@Sun.COM * OR
4127836SJohn.Forte@Sun.COM * 2/ If the number of detaches != number of attached vols
4137836SJohn.Forte@Sun.COM */
4147836SJohn.Forte@Sun.COM op = ip->bi_overflow;
4157836SJohn.Forte@Sun.COM if (op && (((op->ii_flags & IIO_VOL_UPDATE) == 0) ||
4167836SJohn.Forte@Sun.COM (op->ii_detachcnt != op->ii_drefcnt))) {
4177836SJohn.Forte@Sun.COM #ifndef II_MULTIMULTI_TERABYTE
4187836SJohn.Forte@Sun.COM /* assert volume size fits into node_id */
4197836SJohn.Forte@Sun.COM ASSERT(ip->bi_mstchks <= INT32_MAX);
4207836SJohn.Forte@Sun.COM #endif
4217836SJohn.Forte@Sun.COM for (node_id = 0; node_id < ip->bi_mstchks; node_id++) {
4227836SJohn.Forte@Sun.COM if ((node = read_node(ip, node_id)) == NULL) {
4237836SJohn.Forte@Sun.COM DTRACE_PROBE(_iit_reclaim_overflow_end);
424*9093SRamana.Srikanth@Sun.COM return;
4257836SJohn.Forte@Sun.COM }
4267836SJohn.Forte@Sun.COM ii_free_overflow(ip, node->vchunk_id);
4277836SJohn.Forte@Sun.COM release_node(ip, node, node_id);
4287836SJohn.Forte@Sun.COM }
4297836SJohn.Forte@Sun.COM } else {
4307836SJohn.Forte@Sun.COM /* need to reset the overflow volume header */
4317836SJohn.Forte@Sun.COM op->ii_freehead = II_NULLNODE;
4327836SJohn.Forte@Sun.COM op->ii_used = 1; /* we have used the header */
4337836SJohn.Forte@Sun.COM op->ii_unused = op->ii_nchunks - op->ii_used;
4347836SJohn.Forte@Sun.COM (void) update_overflow_header(ip, op);
4357836SJohn.Forte@Sun.COM }
4367836SJohn.Forte@Sun.COM
4377836SJohn.Forte@Sun.COM DTRACE_PROBE(_iit_reclaim_overflow);
4387836SJohn.Forte@Sun.COM
4397836SJohn.Forte@Sun.COM if ((ip->bi_flags & DSW_VOVERFLOW) == DSW_VOVERFLOW) {
4407836SJohn.Forte@Sun.COM mutex_enter(&ip->bi_mutex);
4417836SJohn.Forte@Sun.COM II_FLAG_CLR(DSW_VOVERFLOW, ip);
4427836SJohn.Forte@Sun.COM mutex_exit(&ip->bi_mutex);
4437836SJohn.Forte@Sun.COM }
4447836SJohn.Forte@Sun.COM --iigkstat.spilled_over.value.ul;
4457836SJohn.Forte@Sun.COM
4467836SJohn.Forte@Sun.COM }
4477836SJohn.Forte@Sun.COM
4487836SJohn.Forte@Sun.COM static chunkid_t
ii_alloc_overflow(_ii_info_t * ip)4497836SJohn.Forte@Sun.COM ii_alloc_overflow(_ii_info_t *ip)
4507836SJohn.Forte@Sun.COM {
4517836SJohn.Forte@Sun.COM chunkid_t chunk;
4527836SJohn.Forte@Sun.COM ii_nodelink_t nl;
4537836SJohn.Forte@Sun.COM _ii_overflow_t *op;
4547836SJohn.Forte@Sun.COM int fba;
4557836SJohn.Forte@Sun.COM
4567836SJohn.Forte@Sun.COM if ((op = ip->bi_overflow) == NULL) {
4577836SJohn.Forte@Sun.COM DTRACE_PROBE(_iit_alloc_overflow_end);
4587836SJohn.Forte@Sun.COM return (II_NULLCHUNK); /* no overflow volume attached */
4597836SJohn.Forte@Sun.COM }
4607836SJohn.Forte@Sun.COM
4617836SJohn.Forte@Sun.COM mutex_enter(&(op->ii_mutex));
4627836SJohn.Forte@Sun.COM
4637836SJohn.Forte@Sun.COM DTRACE_PROBE(_iit_alloc_overflow);
4647836SJohn.Forte@Sun.COM
4657836SJohn.Forte@Sun.COM if (op->ii_unused < 1) {
4667836SJohn.Forte@Sun.COM mutex_exit(&(op->ii_mutex));
4677836SJohn.Forte@Sun.COM DTRACE_PROBE(_iit_alloc_overflow_end);
4687836SJohn.Forte@Sun.COM return (II_NULLCHUNK);
4697836SJohn.Forte@Sun.COM }
4707836SJohn.Forte@Sun.COM (void) nsc_reserve(op->ii_dev->bi_fd, NSC_MULTI);
4717836SJohn.Forte@Sun.COM if (op->ii_freehead != II_NULLCHUNK) {
4727836SJohn.Forte@Sun.COM /* pick first from free list */
4737836SJohn.Forte@Sun.COM chunk = op->ii_freehead;
4747836SJohn.Forte@Sun.COM fba = CHUNK_FBA(chunk);
4757836SJohn.Forte@Sun.COM (void) _ii_nsc_io(ip, KS_OVR, op->ii_dev->bi_fd, NSC_RDBUF, fba,
4767836SJohn.Forte@Sun.COM (unsigned char *)&nl, sizeof (nl));
4777836SJohn.Forte@Sun.COM op->ii_freehead = nl.next_chunk;
4787836SJohn.Forte@Sun.COM /* decrease unused count, fix bug 4419956 */
4797836SJohn.Forte@Sun.COM op->ii_unused--;
4807836SJohn.Forte@Sun.COM } else {
4817836SJohn.Forte@Sun.COM /* otherwise pick first unused */
4827836SJohn.Forte@Sun.COM if (op->ii_used > op->ii_nchunks)
4837836SJohn.Forte@Sun.COM chunk = II_NULLCHUNK;
4847836SJohn.Forte@Sun.COM else {
4857836SJohn.Forte@Sun.COM chunk = op->ii_used++;
4867836SJohn.Forte@Sun.COM op->ii_unused--;
4877836SJohn.Forte@Sun.COM }
4887836SJohn.Forte@Sun.COM }
4897836SJohn.Forte@Sun.COM if (chunk != II_NULLCHUNK) {
4907836SJohn.Forte@Sun.COM chunk = II_2OVERFLOW(chunk);
4917836SJohn.Forte@Sun.COM if ((ip->bi_flags&DSW_VOVERFLOW) == 0) {
4927836SJohn.Forte@Sun.COM mutex_enter(&ip->bi_mutex);
4937836SJohn.Forte@Sun.COM II_FLAG_SET(DSW_VOVERFLOW, ip);
4947836SJohn.Forte@Sun.COM mutex_exit(&ip->bi_mutex);
4957836SJohn.Forte@Sun.COM ++iigkstat.spilled_over.value.ul;
4967836SJohn.Forte@Sun.COM }
4977836SJohn.Forte@Sun.COM }
4987836SJohn.Forte@Sun.COM (void) update_overflow_header(ip, op);
4997836SJohn.Forte@Sun.COM nsc_release(op->ii_dev->bi_fd);
5007836SJohn.Forte@Sun.COM mutex_exit(&(op->ii_mutex));
5017836SJohn.Forte@Sun.COM
5027836SJohn.Forte@Sun.COM return (chunk);
5037836SJohn.Forte@Sun.COM }
5047836SJohn.Forte@Sun.COM /*
5057836SJohn.Forte@Sun.COM * Find or insert key into search tree.
5067836SJohn.Forte@Sun.COM */
5077836SJohn.Forte@Sun.COM
5087836SJohn.Forte@Sun.COM chunkid_t
ii_tsearch(_ii_info_t * ip,chunkid_t chunk_id)5097836SJohn.Forte@Sun.COM ii_tsearch(_ii_info_t *ip, chunkid_t chunk_id)
5107836SJohn.Forte@Sun.COM /* Address of the root of the tree */
5117836SJohn.Forte@Sun.COM {
5127836SJohn.Forte@Sun.COM NODE *rootp = NULL;
5137836SJohn.Forte@Sun.COM chunkid_t n; /* New node id if key not found */
5147836SJohn.Forte@Sun.COM
5157836SJohn.Forte@Sun.COM if ((rootp = read_node(ip, chunk_id)) == NULL) {
5167836SJohn.Forte@Sun.COM DTRACE_PROBE(_iit_tsearch_end);
5177836SJohn.Forte@Sun.COM return (II_NULLNODE);
5187836SJohn.Forte@Sun.COM }
5197836SJohn.Forte@Sun.COM n = rootp->vchunk_id;
5207836SJohn.Forte@Sun.COM if (n != II_NULLCHUNK) { /* chunk allocated, return location */
5217836SJohn.Forte@Sun.COM release_node(ip, rootp, 0);
5227836SJohn.Forte@Sun.COM DTRACE_PROBE(_iit_tsearch_end);
5237836SJohn.Forte@Sun.COM return (n);
5247836SJohn.Forte@Sun.COM }
5257836SJohn.Forte@Sun.COM n = alloc_chunk(ip);
5267836SJohn.Forte@Sun.COM if (n != II_NULLCHUNK) {
5277836SJohn.Forte@Sun.COM rootp->vchunk_id = n;
5287836SJohn.Forte@Sun.COM write_node(ip, rootp, chunk_id);
5297836SJohn.Forte@Sun.COM } else
5307836SJohn.Forte@Sun.COM release_node(ip, rootp, 0);
5317836SJohn.Forte@Sun.COM
5327836SJohn.Forte@Sun.COM return (n);
5337836SJohn.Forte@Sun.COM }
5347836SJohn.Forte@Sun.COM
5357836SJohn.Forte@Sun.COM /* Delete node with key chunkid */
5367836SJohn.Forte@Sun.COM void
ii_tdelete(_ii_info_t * ip,chunkid_t chunkid)5377836SJohn.Forte@Sun.COM ii_tdelete(_ii_info_t *ip,
5387836SJohn.Forte@Sun.COM chunkid_t chunkid) /* Key to be deleted */
5397836SJohn.Forte@Sun.COM {
5407836SJohn.Forte@Sun.COM NODE *np = NULL;
5417836SJohn.Forte@Sun.COM
5427836SJohn.Forte@Sun.COM if ((np = read_node(ip, chunkid)) == NULL) {
5437836SJohn.Forte@Sun.COM DTRACE_PROBE(_iit_tdelete_end);
5447836SJohn.Forte@Sun.COM return;
5457836SJohn.Forte@Sun.COM }
5467836SJohn.Forte@Sun.COM
5477836SJohn.Forte@Sun.COM ASSERT(np->vchunk_id != II_NULLCHUNK);
5487836SJohn.Forte@Sun.COM free_node(ip, np, chunkid);
5497836SJohn.Forte@Sun.COM np->vchunk_id = II_NULLCHUNK;
5507836SJohn.Forte@Sun.COM write_node(ip, np, chunkid);
5517836SJohn.Forte@Sun.COM
5527836SJohn.Forte@Sun.COM }
5537836SJohn.Forte@Sun.COM
5547836SJohn.Forte@Sun.COM /*
5557836SJohn.Forte@Sun.COM * initialise an empty map for ip
5567836SJohn.Forte@Sun.COM */
5577836SJohn.Forte@Sun.COM
5587836SJohn.Forte@Sun.COM int
ii_tinit(_ii_info_t * ip)5597836SJohn.Forte@Sun.COM ii_tinit(_ii_info_t *ip)
5607836SJohn.Forte@Sun.COM {
5617836SJohn.Forte@Sun.COM int rc = 0;
5627836SJohn.Forte@Sun.COM
5637836SJohn.Forte@Sun.COM /* overflow can't be attached before first call to this function */
5647836SJohn.Forte@Sun.COM if (ip->bi_overflow)
5657836SJohn.Forte@Sun.COM ii_reclaim_overflow(ip);
5667836SJohn.Forte@Sun.COM
5677836SJohn.Forte@Sun.COM mutex_enter(&ip->bi_chksmutex);
5687836SJohn.Forte@Sun.COM ip->bi_shdfchk = II_NULLCHUNK; /* set freelist to empty chain */
5697836SJohn.Forte@Sun.COM ip->bi_shdchkused = 0;
5707836SJohn.Forte@Sun.COM
5717836SJohn.Forte@Sun.COM /* fill index (bi_mstchks size) with II_NULLCHUNK */
5727836SJohn.Forte@Sun.COM rc = node_fba_fill(ip, ip->bi_mstchks, II_NULLCHUNK);
5737836SJohn.Forte@Sun.COM if (rc == 0)
5747836SJohn.Forte@Sun.COM rc = update_tree_header(ip);
5757836SJohn.Forte@Sun.COM mutex_exit(&ip->bi_chksmutex);
5767836SJohn.Forte@Sun.COM
5777836SJohn.Forte@Sun.COM return (rc);
5787836SJohn.Forte@Sun.COM }
5797836SJohn.Forte@Sun.COM
5807836SJohn.Forte@Sun.COM /*
5817836SJohn.Forte@Sun.COM * Calculate the size of map space provided by a bitmap volume with
5827836SJohn.Forte@Sun.COM * tree_len fba's spare for the tree.
5837836SJohn.Forte@Sun.COM */
5847836SJohn.Forte@Sun.COM
5857836SJohn.Forte@Sun.COM nsc_size_t
ii_btsize(nsc_size_t tree_len)5867836SJohn.Forte@Sun.COM ii_btsize(nsc_size_t tree_len)
5877836SJohn.Forte@Sun.COM {
5887836SJohn.Forte@Sun.COM nsc_size_t nchunks;
5897836SJohn.Forte@Sun.COM
5907836SJohn.Forte@Sun.COM nchunks = tree_len * nodes_per_fba;
5917836SJohn.Forte@Sun.COM
5927836SJohn.Forte@Sun.COM if (ii_debug > 1)
5937836SJohn.Forte@Sun.COM cmn_err(CE_NOTE,
594*9093SRamana.Srikanth@Sun.COM "!ii_btsize: bitmap with %" NSC_SZFMT
5957836SJohn.Forte@Sun.COM " spare fba's will map %" NSC_SZFMT " chunks",
596*9093SRamana.Srikanth@Sun.COM tree_len, nchunks);
5977836SJohn.Forte@Sun.COM
5987836SJohn.Forte@Sun.COM return (nchunks);
5997836SJohn.Forte@Sun.COM }
600