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 (c) 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 #include <stddef.h> 27 #include <strings.h> 28 29 #include "../common/sw_impl.h" 30 31 /* 32 * We maintain a single list of all active cases across all 33 * subsidary diagnosis "modules". We also offer some serialization 34 * services to them. 35 * 36 * To open a new case a subsidiary engine should use swde_case_open 37 * indicating the subsidiary id (from which we lookup the enum sw_casetype) 38 * and, optionally, a pointer to a structure for serialization and its size. 39 * 40 * For each case opened with swde_case_open we maintain an swde_case_t 41 * structure in-core. Embedded in this is the swde_case_data_t with 42 * information we need to keep track of and manage this case - it's 43 * case type, buffer name used for the sub-de-private data (if any) 44 * and the size of the sub-de-private structure. It is this 45 * embedded structure which is serialized as the "casedata" buffer, 46 * while the subsidiary-private structure is serialized into another buffer 47 * "casedata_<casetype-in-hex>". 48 * 49 * The subsidiary-private data structure, if any, is required to start 50 * with a uint32_t recording the data structure version. This 51 * version is also specified as an argument to swde_case_open, and 52 * we note it in the "casedata" buffer we write out and require 53 * a match on restore. 54 * 55 * When we unserialize we restore our management structure as well as 56 * the sub-de-private structure. 57 * 58 * Here's how serialization works: 59 * 60 * In swde_case_open we create a case data buffer for the case named 61 * SW_CASE_DATA_BUFNAME. We write the buffer out after filling in the 62 * structure version and recording the type of case this is, and if there 63 * is data for the subsidiary then we call swde_subdata to note the 64 * size and version of that data in the case data buf and then to create 65 * and write the subdata in a buffer named SW_CASE_DATA_BUFNAME_<casetype>. 66 * 67 * If the subsidiary updates its case data it is required to call 68 * swde_case_data_write. This just calls fmd_buf_write for the subsidiary 69 * buffer name. 70 * 71 * A subsidiary can retrieve its private data buffer for a case using 72 * swde_case_data. This also fills a uint32_t with the version of the 73 * buffer that we have for this subsidiary; if that is an old version 74 * the subsidiary can cast appropriately and/or upgrade the buffer as 75 * below. 76 * 77 * When the host module is reloaded it calls swde_case_init to iterate 78 * through all cases we own. For each we call swde_case_unserialize 79 * which restores our case tracking data and any subsidiary-private 80 * data that our case data notes. We then call swde_case_verify which 81 * calls any registered verify function in the subsidiary owner, and if this 82 * returns 0 the case is closed. 83 * 84 * After initial write, we don't usually have to update the 85 * SW_CASE_DATA_BUFNAME buffer unless the subsidiary changes the size or 86 * version of its private buffer. To do that the subsidiary must call 87 * swde_case_data_upgrade. In that function we destroy the old subsidiary 88 * buffer and, if there is still a subsidiary data structure, create a 89 * new buffer appropriately sized and call swde_subdata to write it out 90 * after updating our case structure with new size etc. Finally we write 91 * out our updated case data structure. 92 */ 93 94 #define SW_CASE_DATA_BUFNAME "casedata" 95 96 #define SW_CASE_DATA_VERSION_INITIAL 1 97 #define SW_CASE_DATA_BUFNAMELEN 18 /* 8 + 1 + 8 + 1 */ 98 typedef struct swde_case_data { 99 uint32_t sc_version; /* buffer structure version */ 100 int32_t sc_type; /* enum sw_casetype */ 101 uint32_t sc_sub_bufvers; /* version expected in subsidiary */ 102 char sc_sub_bufname[SW_CASE_DATA_BUFNAMELEN]; /* subsidiary bufname */ 103 int32_t sc_sub_bufsz; /* subsidiary structure size */ 104 } swde_case_data_t; 105 106 #define SW_CASE_DATA_VERSION SW_CASE_DATA_VERSION_INITIAL 107 108 /* 109 * In-core case structure. 110 */ 111 typedef struct swde_case { 112 fmd_case_t *swc_fmdcase; /* fmd case handle */ 113 swde_case_data_t swc_data; /* case data for serialization */ 114 void *swc_subdata; /* subsidiary data for serialization */ 115 } swde_case_t; 116 117 static void 118 swde_case_associate(fmd_hdl_t *hdl, fmd_case_t *cp, swde_case_t *scp, 119 void *subdata) 120 { 121 scp->swc_fmdcase = cp; 122 scp->swc_subdata = subdata; 123 fmd_case_setspecific(hdl, cp, scp); 124 } 125 126 static void 127 swde_case_unserialize(fmd_hdl_t *hdl, fmd_case_t *cp) 128 { 129 swde_case_t *scp; 130 swde_case_data_t *datap; 131 void *subdata; 132 size_t sz; 133 134 scp = fmd_hdl_zalloc(hdl, sizeof (*scp), FMD_SLEEP); 135 datap = &scp->swc_data; 136 137 fmd_buf_read(hdl, cp, SW_CASE_DATA_BUFNAME, datap, sizeof (*datap)); 138 139 if (datap->sc_version > SW_CASE_DATA_VERSION_INITIAL) { 140 fmd_hdl_free(hdl, scp, sizeof (*scp)); 141 return; 142 } 143 144 if ((sz = datap->sc_sub_bufsz) != 0) { 145 subdata = fmd_hdl_alloc(hdl, sz, FMD_SLEEP); 146 fmd_buf_read(hdl, cp, datap->sc_sub_bufname, subdata, sz); 147 148 if (*((uint32_t *)subdata) != datap->sc_sub_bufvers) { 149 fmd_hdl_abort(hdl, "unserialize: expected subdata " 150 "version %u but received %u\n", 151 datap->sc_sub_bufvers, *((uint32_t *)subdata)); 152 } 153 } 154 155 swde_case_associate(hdl, cp, scp, subdata); 156 } 157 158 static void 159 swde_subdata(fmd_hdl_t *hdl, fmd_case_t *cp, enum sw_casetype type, 160 swde_case_t *scp, uint32_t subdata_vers, void *subdata, size_t subdata_sz) 161 { 162 swde_case_data_t *datap = &scp->swc_data; 163 164 if (*((uint32_t *)subdata) != subdata_vers) 165 fmd_hdl_abort(hdl, "swde_subdata: subdata version " 166 "does not match argument\n"); 167 168 (void) snprintf(datap->sc_sub_bufname, sizeof (datap->sc_sub_bufname), 169 "%s_%08x", SW_CASE_DATA_BUFNAME, type); 170 171 datap->sc_sub_bufsz = subdata_sz; 172 datap->sc_sub_bufvers = subdata_vers; 173 fmd_buf_create(hdl, cp, datap->sc_sub_bufname, subdata_sz); 174 fmd_buf_write(hdl, cp, datap->sc_sub_bufname, subdata, subdata_sz); 175 } 176 177 fmd_case_t * 178 swde_case_open(fmd_hdl_t *hdl, id_t who, char *req_uuid, 179 uint32_t subdata_vers, void *subdata, size_t subdata_sz) 180 { 181 enum sw_casetype ct = sw_id_to_casetype(hdl, who); 182 swde_case_data_t *datap; 183 swde_case_t *scp; 184 fmd_case_t *cp; 185 186 if (ct == SW_CASE_NONE) 187 fmd_hdl_abort(hdl, "swde_case_open for type SW_CASE_NONE\n"); 188 189 if (subdata != NULL && subdata_sz <= sizeof (uint32_t) || 190 subdata_sz != 0 && subdata == NULL) 191 fmd_hdl_abort(hdl, "swde_case_open: bad subdata\n", ct); 192 193 scp = fmd_hdl_zalloc(hdl, sizeof (*scp), FMD_SLEEP); 194 datap = &scp->swc_data; 195 196 if (req_uuid == NULL) { 197 cp = fmd_case_open(hdl, (void *)scp); 198 } else { 199 cp = fmd_case_open_uuid(hdl, req_uuid, (void *)scp); 200 if (cp == NULL) { 201 fmd_hdl_free(hdl, scp, sizeof (*scp)); 202 return (NULL); 203 } 204 } 205 206 fmd_buf_create(hdl, cp, SW_CASE_DATA_BUFNAME, sizeof (*datap)); 207 datap->sc_version = SW_CASE_DATA_VERSION_INITIAL; 208 datap->sc_type = ct; 209 210 if (subdata) 211 swde_subdata(hdl, cp, ct, scp, subdata_vers, subdata, 212 subdata_sz); 213 214 fmd_buf_write(hdl, cp, SW_CASE_DATA_BUFNAME, datap, sizeof (*datap)); 215 swde_case_associate(hdl, cp, scp, subdata); 216 217 return (cp); 218 } 219 220 /* 221 * fmdo_close entry point for software-diagnosis 222 */ 223 void 224 swde_close(fmd_hdl_t *hdl, fmd_case_t *cp) 225 { 226 swde_case_t *scp = fmd_case_getspecific(hdl, cp); 227 swde_case_data_t *datap = &scp->swc_data; 228 swsub_case_close_func_t *closefunc; 229 230 if ((closefunc = sw_sub_case_close_func(hdl, datap->sc_type)) != NULL) 231 closefunc(hdl, cp); 232 233 /* 234 * Now that the sub-de has had a chance to clean up, do some ourselves. 235 * Note that we free the sub-de-private subdata structure. 236 */ 237 238 if (scp->swc_subdata) { 239 fmd_hdl_free(hdl, scp->swc_subdata, datap->sc_sub_bufsz); 240 fmd_buf_destroy(hdl, cp, datap->sc_sub_bufname); 241 } 242 243 fmd_buf_destroy(hdl, cp, SW_CASE_DATA_BUFNAME); 244 245 fmd_hdl_free(hdl, scp, sizeof (*scp)); 246 } 247 248 fmd_case_t * 249 swde_case_first(fmd_hdl_t *hdl, id_t who) 250 { 251 enum sw_casetype ct = sw_id_to_casetype(hdl, who); 252 swde_case_t *scp; 253 fmd_case_t *cp; 254 255 if (ct == SW_CASE_NONE) 256 fmd_hdl_abort(hdl, "swde_case_first for type SW_CASE_NONE\n"); 257 258 for (cp = fmd_case_next(hdl, NULL); cp; cp = fmd_case_next(hdl, cp)) { 259 scp = fmd_case_getspecific(hdl, cp); 260 if (scp->swc_data.sc_type == ct) 261 break; 262 } 263 264 return (cp); 265 } 266 267 fmd_case_t * 268 swde_case_next(fmd_hdl_t *hdl, fmd_case_t *lastcp) 269 { 270 swde_case_t *scp; 271 fmd_case_t *cp; 272 int ct; 273 274 if (lastcp == NULL) 275 fmd_hdl_abort(hdl, "swde_case_next called for NULL lastcp\n"); 276 277 scp = fmd_case_getspecific(hdl, lastcp); 278 ct = scp->swc_data.sc_type; 279 280 cp = lastcp; 281 while ((cp = fmd_case_next(hdl, cp)) != NULL) { 282 scp = fmd_case_getspecific(hdl, cp); 283 if (scp->swc_data.sc_type == ct) 284 break; 285 } 286 287 return (cp); 288 } 289 290 void * 291 swde_case_data(fmd_hdl_t *hdl, fmd_case_t *cp, uint32_t *svp) 292 { 293 swde_case_t *scp = fmd_case_getspecific(hdl, cp); 294 swde_case_data_t *datap = &scp->swc_data; 295 296 if (svp != NULL && scp->swc_subdata) 297 *svp = datap->sc_sub_bufvers; 298 299 return (scp->swc_subdata); 300 } 301 302 void 303 swde_case_data_write(fmd_hdl_t *hdl, fmd_case_t *cp) 304 { 305 swde_case_t *scp = fmd_case_getspecific(hdl, cp); 306 swde_case_data_t *datap = &scp->swc_data; 307 308 if (scp->swc_subdata == NULL) 309 return; 310 311 fmd_buf_write(hdl, cp, scp->swc_data.sc_sub_bufname, 312 scp->swc_subdata, datap->sc_sub_bufsz); 313 } 314 315 void 316 swde_case_data_upgrade(fmd_hdl_t *hdl, fmd_case_t *cp, uint32_t subdata_vers, 317 void *subdata, size_t subdata_sz) 318 { 319 swde_case_t *scp = fmd_case_getspecific(hdl, cp); 320 swde_case_data_t *datap = &scp->swc_data; 321 322 if (scp->swc_subdata) { 323 fmd_buf_destroy(hdl, cp, datap->sc_sub_bufname); 324 fmd_hdl_free(hdl, scp->swc_subdata, datap->sc_sub_bufsz); 325 scp->swc_subdata = NULL; 326 datap->sc_sub_bufsz = 0; 327 datap->sc_sub_bufname[0] = '\0'; 328 } 329 330 if (subdata != NULL) { 331 scp->swc_subdata = subdata; 332 swde_subdata(hdl, cp, datap->sc_type, scp, subdata_vers, 333 subdata, subdata_sz); 334 } 335 336 fmd_buf_write(hdl, scp->swc_fmdcase, SW_CASE_DATA_BUFNAME, 337 datap, sizeof (*datap)); 338 } 339 340 static void 341 swde_case_verify(fmd_hdl_t *hdl, fmd_case_t *cp) 342 { 343 swde_case_t *scp = fmd_case_getspecific(hdl, cp); 344 swde_case_data_t *datap = &scp->swc_data; 345 sw_case_vrfy_func_t *vrfy_func; 346 347 if ((vrfy_func = sw_sub_case_vrfy_func(hdl, datap->sc_type)) != NULL) { 348 if (vrfy_func(hdl, cp) == 0) 349 fmd_case_close(hdl, cp); 350 } 351 } 352 353 void 354 swde_case_init(fmd_hdl_t *hdl) 355 { 356 fmd_case_t *cp; 357 358 for (cp = fmd_case_next(hdl, NULL); cp; cp = fmd_case_next(hdl, cp)) { 359 swde_case_unserialize(hdl, cp); 360 swde_case_verify(hdl, cp); 361 } 362 } 363 364 /*ARGSUSED*/ 365 void 366 swde_case_fini(fmd_hdl_t *hdl) 367 { 368 } 369