1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/param.h>
31 #include <sys/mdesc.h>
32 #include <sys/mdesc_impl.h>
33 
34 md_t *
md_init_intern(uint64_t * ptr,void * (* allocp)(size_t),void (* freep)(void *,size_t))35 md_init_intern(uint64_t *ptr,  void *(*allocp)(size_t),
36 	    void (*freep)(void *, size_t))
37 {
38 	md_impl_t	*mdp;
39 	int		idx;
40 	int		count;
41 	int		done;
42 	uint64_t	gen;
43 	mde_str_cookie_t root_name;
44 
45 	/*
46 	 * Very basic checkup for alignment to avoid
47 	 * bus error issues.
48 	 */
49 	if ((((uintptr_t)ptr) & 7) != 0)
50 		return (NULL);
51 
52 	mdp = (md_impl_t *)allocp(sizeof (md_impl_t));
53 
54 	if (mdp == NULL)
55 		return (NULL);
56 
57 	mdp->allocp = allocp;
58 	mdp->freep = freep;
59 
60 	mdp->caddr = (char *)ptr;
61 
62 	/*
63 	 * setup internal structures
64 	 */
65 
66 	mdp->headerp = (md_header_t *)mdp->caddr;
67 
68 	if (mdtoh32(mdp->headerp->transport_version) != MD_TRANSPORT_VERSION) {
69 		goto cleanup_nohash;
70 	}
71 
72 	mdp->node_blk_size = mdtoh32(mdp->headerp->node_blk_sz);
73 	mdp->name_blk_size = mdtoh32(mdp->headerp->name_blk_sz);
74 	mdp->data_blk_size = mdtoh32(mdp->headerp->data_blk_sz);
75 
76 	mdp->size = MD_HEADER_SIZE + mdp->node_blk_size +
77 	    mdp->name_blk_size + mdp->data_blk_size;
78 
79 	mdp->mdep = (md_element_t *)(mdp->caddr + MD_HEADER_SIZE);
80 	mdp->namep = (char *)(mdp->caddr + MD_HEADER_SIZE + mdp->node_blk_size);
81 	mdp->datap = (uint8_t *)(mdp->caddr + MD_HEADER_SIZE +
82 	    mdp->name_blk_size + mdp->node_blk_size);
83 
84 	mdp->root_node = MDE_INVAL_ELEM_COOKIE;
85 
86 
87 	/*
88 	 * Should do a lot more sanity checking here.
89 	 */
90 
91 	/*
92 	 * Should initialize a name hash here if we intend to use one
93 	 */
94 
95 	/*
96 	 * Setup to find the root node
97 	 */
98 	root_name = md_find_name((md_t *)mdp, "root");
99 	if (root_name == MDE_INVAL_STR_COOKIE) {
100 		goto cleanup;
101 	}
102 
103 	/*
104 	 * One more property we need is the count of nodes in the
105 	 * DAG, not just the number of elements.
106 	 *
107 	 * We try and pickup the root node along the way here.
108 	 */
109 
110 	for (done = 0, idx = 0, count = 0; !done; ) {
111 		md_element_t *np;
112 
113 		np = &(mdp->mdep[idx]);
114 
115 		switch (MDE_TAG(np)) {
116 		case MDET_LIST_END:
117 			done = 1;
118 			break;
119 
120 		case MDET_NODE:
121 			if (root_name == MDE_NAME(np)) {
122 				if (mdp->root_node != MDE_INVAL_ELEM_COOKIE) {
123 					/* Gah .. more than one root */
124 					goto cleanup;
125 				}
126 				mdp->root_node = (mde_cookie_t)idx;
127 			}
128 			idx = MDE_PROP_INDEX(np);
129 			count++;
130 			break;
131 
132 		default:
133 			idx++;	/* ignore */
134 		}
135 	}
136 
137 	/*
138 	 * Ensure there is a root node
139 	 */
140 	if (mdp->root_node == MDE_INVAL_ELEM_COOKIE) {
141 		goto cleanup;
142 	}
143 
144 	/*
145 	 * Register the counts
146 	 */
147 
148 	mdp->element_count = idx + 1;	/* include LIST_END */
149 	mdp->node_count = count;
150 
151 	/*
152 	 * Final sanity check that everything adds up
153 	 */
154 	if (mdp->element_count != (mdp->node_blk_size / MD_ELEMENT_SIZE))
155 		goto cleanup;
156 
157 	mdp->md_magic = LIBMD_MAGIC;
158 
159 	/*
160 	 * Setup MD generation
161 	 */
162 	if (md_get_prop_val((md_t *)mdp, mdp->root_node,
163 	    "md-generation#", &gen) != 0)
164 		mdp->gen = MDESC_INVAL_GEN;
165 	else
166 		mdp->gen = gen;
167 
168 	return ((md_t *)mdp);
169 
170 cleanup:
171 	/*
172 	 * Clean up here - including a name hash if
173 	 * we build one.
174 	 */
175 
176 cleanup_nohash:
177 	mdp->freep(mdp, sizeof (md_impl_t));
178 	return (NULL);
179 }
180