Print this page
patch cleanup
6659 nvlist_free(NULL) is a no-op
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/os/retire_store.c
+++ new/usr/src/uts/common/os/retire_store.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 -#pragma ident "%Z%%M% %I% %E% SMI"
27 -
28 26 #include <sys/ddi.h>
29 27 #include <sys/sunddi.h>
30 28 #include <sys/sunndi.h>
31 29 #include <sys/ddi_impldefs.h>
32 30 #include <sys/ddi_implfuncs.h>
33 31 #include <sys/list.h>
34 32 #include <sys/reboot.h>
35 33 #include <sys/sysmacros.h>
36 34 #include <sys/console.h>
37 35 #include <sys/devcache.h>
38 36
39 37 /*
40 38 * The nvpair name in the I/O retire specific sub-nvlist
41 39 */
42 40 #define RIO_STORE_VERSION_STR "rio-store-version"
43 41 #define RIO_STORE_MAGIC_STR "rio-store-magic"
44 42 #define RIO_STORE_FLAGS_STR "rio-store-flags"
45 43
46 44 #define RIO_STORE_VERSION_1 1
47 45 #define RIO_STORE_VERSION RIO_STORE_VERSION_1
48 46
49 47 /*
50 48 * decoded retire list element
51 49 */
52 50
53 51 typedef enum rio_store_flags {
54 52 RIO_STORE_F_INVAL = 0,
55 53 RIO_STORE_F_RETIRED = 1,
56 54 RIO_STORE_F_BYPASS = 2
57 55 } rio_store_flags_t;
58 56
59 57 typedef struct rio_store {
60 58 char *rst_devpath;
61 59 rio_store_flags_t rst_flags;
62 60 list_node_t rst_next;
63 61 } rio_store_t;
64 62
65 63 #define RIO_STORE_MAGIC 0x601fcace /* retire */
66 64
67 65 static int rio_store_decode(nvf_handle_t nvfh, nvlist_t *line_nvl, char *name);
68 66 static int rio_store_encode(nvf_handle_t nvfh, nvlist_t **ret_nvl);
69 67 static void retire_list_free(nvf_handle_t nvfh);
70 68
71 69
72 70 /*
73 71 * Retire I/O persistent store registration info
74 72 */
75 73 static nvf_ops_t rio_store_ops = {
76 74 "/etc/devices/retire_store", /* path to store */
77 75 rio_store_decode, /* decode nvlist into retire_list */
78 76 rio_store_encode, /* encode retire_list into nvlist */
79 77 retire_list_free, /* free retire_list */
80 78 NULL /* write complete callback */
81 79 };
82 80
83 81 static nvf_handle_t rio_store_handle;
84 82 static char store_path[MAXPATHLEN];
85 83 static int store_debug = 0;
86 84 static int bypass_msg = 0;
87 85 static int retire_msg = 0;
88 86
89 87 #define STORE_DEBUG 0x0001
90 88 #define STORE_TRACE 0x0002
91 89
92 90 #define STORE_DBG(args) if (store_debug & STORE_DEBUG) cmn_err args
93 91 #define STORE_TRC(args) if (store_debug & STORE_TRACE) cmn_err args
94 92
95 93 /*
96 94 * We don't use the simple read disable offered by the
97 95 * caching framework (see devcache.c) as it will not
98 96 * have the desired effect of bypassing the persistent
99 97 * store. A simple read disable will
100 98 *
101 99 * 1. cause any additions to the cache to destroy the
102 100 * existing on-disk cache
103 101 *
104 102 * 2. prevent deletions from the existing on-disk
105 103 * cache which is needed for recovery from bad
106 104 * retire decisions.
107 105 *
108 106 * Use the following tunable instead
109 107 *
110 108 */
111 109 int ddi_retire_store_bypass = 0;
112 110
113 111
114 112
115 113 /*
116 114 * Initialize retire store data structures
117 115 */
118 116 void
119 117 retire_store_init(void)
120 118 {
121 119 if (boothowto & RB_ASKNAME) {
122 120
123 121 printf("Retire store [%s] (/dev/null to bypass): ",
124 122 rio_store_ops.nvfr_cache_path);
125 123 console_gets(store_path, sizeof (store_path) - 1);
126 124 store_path[sizeof (store_path) - 1] = '\0';
127 125
128 126 if (strcmp(store_path, "/dev/null") == 0) {
129 127 ddi_retire_store_bypass = 1;
130 128 } else if (store_path[0] != '\0') {
131 129 if (store_path[0] != '/') {
132 130 printf("Invalid store path: %s. Using default"
133 131 "\n", store_path);
134 132 } else {
135 133 rio_store_ops.nvfr_cache_path = store_path;
136 134 }
137 135 }
138 136 }
139 137
140 138 rio_store_handle = nvf_register_file(&rio_store_ops);
141 139
142 140 list_create(nvf_list(rio_store_handle), sizeof (rio_store_t),
143 141 offsetof(rio_store_t, rst_next));
144 142 }
145 143
146 144 /*
147 145 * Read and populate the in-core retire store
148 146 */
149 147 void
150 148 retire_store_read(void)
151 149 {
152 150 rw_enter(nvf_lock(rio_store_handle), RW_WRITER);
153 151 ASSERT(list_head(nvf_list(rio_store_handle)) == NULL);
154 152 (void) nvf_read_file(rio_store_handle);
155 153 rw_exit(nvf_lock(rio_store_handle));
156 154 STORE_DBG((CE_NOTE, "Read on-disk retire store"));
157 155 }
158 156
159 157 static void
160 158 rio_store_free(rio_store_t *rsp)
161 159 {
162 160 int flag_mask = RIO_STORE_F_RETIRED|RIO_STORE_F_BYPASS;
163 161
164 162 ASSERT(rsp);
165 163 ASSERT(rsp->rst_devpath);
166 164 ASSERT(rsp->rst_flags & RIO_STORE_F_RETIRED);
167 165 ASSERT(!(rsp->rst_flags & ~flag_mask));
168 166
169 167 STORE_TRC((CE_NOTE, "store: freed path: %s", rsp->rst_devpath));
170 168
171 169 kmem_free(rsp->rst_devpath, strlen(rsp->rst_devpath) + 1);
172 170 kmem_free(rsp, sizeof (*rsp));
173 171 }
174 172
175 173 static void
176 174 retire_list_free(nvf_handle_t nvfh)
177 175 {
178 176 list_t *listp;
179 177 rio_store_t *rsp;
180 178
181 179 ASSERT(nvfh == rio_store_handle);
182 180 ASSERT(RW_WRITE_HELD(nvf_lock(nvfh)));
183 181
184 182 listp = nvf_list(nvfh);
185 183 while (rsp = list_head(listp)) {
186 184 list_remove(listp, rsp);
187 185 rio_store_free(rsp);
188 186 }
189 187
190 188 STORE_DBG((CE_NOTE, "store: freed retire list"));
191 189 }
192 190
193 191 static int
194 192 rio_store_decode(nvf_handle_t nvfh, nvlist_t *line_nvl, char *name)
195 193 {
196 194 rio_store_t *rsp;
197 195 int32_t version;
198 196 int32_t magic;
199 197 int32_t flags;
200 198 int rval;
201 199
202 200 ASSERT(nvfh == rio_store_handle);
203 201 ASSERT(RW_WRITE_HELD(nvf_lock(nvfh)));
204 202 ASSERT(name);
205 203
206 204 version = 0;
207 205 rval = nvlist_lookup_int32(line_nvl, RIO_STORE_VERSION_STR, &version);
208 206 if (rval != 0 || version != RIO_STORE_VERSION) {
209 207 return (EINVAL);
210 208 }
211 209
212 210 magic = 0;
213 211 rval = nvlist_lookup_int32(line_nvl, RIO_STORE_MAGIC_STR, &magic);
214 212 if (rval != 0 || magic != RIO_STORE_MAGIC) {
215 213 return (EINVAL);
216 214 }
217 215
218 216 flags = 0;
219 217 rval = nvlist_lookup_int32(line_nvl, RIO_STORE_FLAGS_STR, &flags);
220 218 if (rval != 0 || flags != RIO_STORE_F_RETIRED) {
221 219 return (EINVAL);
222 220 }
223 221
224 222 if (ddi_retire_store_bypass) {
225 223 flags |= RIO_STORE_F_BYPASS;
226 224 if (!bypass_msg) {
227 225 bypass_msg = 1;
228 226 cmn_err(CE_WARN,
229 227 "Bypassing retire store /etc/devices/retire_store");
230 228 }
231 229 }
232 230
233 231 rsp = kmem_zalloc(sizeof (rio_store_t), KM_SLEEP);
234 232 rsp->rst_devpath = i_ddi_strdup(name, KM_SLEEP);
235 233 rsp->rst_flags = flags;
236 234 list_insert_tail(nvf_list(nvfh), rsp);
237 235
238 236 STORE_TRC((CE_NOTE, "store: added to retire list: %s", name));
239 237 if (!retire_msg) {
240 238 retire_msg = 1;
241 239 cmn_err(CE_NOTE, "One or more I/O devices have been retired");
242 240 }
243 241
244 242 return (0);
245 243 }
246 244
247 245 static int
248 246 rio_store_encode(nvf_handle_t nvfh, nvlist_t **ret_nvl)
249 247 {
250 248 nvlist_t *nvl;
251 249 nvlist_t *line_nvl;
252 250 list_t *listp;
253 251 rio_store_t *rsp;
254 252 int rval;
255 253
256 254 ASSERT(nvfh == rio_store_handle);
257 255 ASSERT(RW_WRITE_HELD(nvf_lock(nvfh)));
258 256
259 257 *ret_nvl = NULL;
260 258
261 259 nvl = NULL;
262 260 rval = nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP);
263 261 if (rval != 0) {
264 262 return (DDI_FAILURE);
265 263 }
266 264
267 265 listp = nvf_list(nvfh);
268 266 for (rsp = list_head(listp); rsp; rsp = list_next(listp, rsp)) {
269 267 int flag_mask = RIO_STORE_F_RETIRED|RIO_STORE_F_BYPASS;
270 268 int flags;
271 269 ASSERT(rsp->rst_devpath);
272 270 ASSERT(!(rsp->rst_flags & ~flag_mask));
273 271
274 272 line_nvl = NULL;
275 273 rval = nvlist_alloc(&line_nvl, NV_UNIQUE_NAME, KM_SLEEP);
276 274 if (rval != 0) {
277 275 line_nvl = NULL;
278 276 goto error;
279 277 }
280 278
281 279 rval = nvlist_add_int32(line_nvl, RIO_STORE_VERSION_STR,
282 280 RIO_STORE_VERSION);
283 281 if (rval != 0) {
284 282 goto error;
285 283 }
286 284 rval = nvlist_add_int32(line_nvl, RIO_STORE_MAGIC_STR,
287 285 RIO_STORE_MAGIC);
288 286 if (rval != 0) {
289 287 goto error;
290 288 }
291 289
292 290 /* don't save the bypass flag */
293 291 flags = RIO_STORE_F_RETIRED;
294 292 rval = nvlist_add_int32(line_nvl, RIO_STORE_FLAGS_STR,
295 293 flags);
296 294 if (rval != 0) {
297 295 goto error;
298 296 }
299 297
300 298 rval = nvlist_add_nvlist(nvl, rsp->rst_devpath, line_nvl);
301 299 if (rval != 0) {
302 300 goto error;
↓ open down ↓ |
265 lines elided |
↑ open up ↑ |
303 301 }
304 302 nvlist_free(line_nvl);
305 303 line_nvl = NULL;
306 304 }
307 305
308 306 *ret_nvl = nvl;
309 307 STORE_DBG((CE_NOTE, "packed retire list into nvlist"));
310 308 return (DDI_SUCCESS);
311 309
312 310 error:
313 - if (line_nvl)
314 - nvlist_free(line_nvl);
311 + nvlist_free(line_nvl);
315 312 ASSERT(nvl);
316 313 nvlist_free(nvl);
317 314 return (DDI_FAILURE);
318 315 }
319 316
320 317 int
321 318 e_ddi_retire_persist(char *devpath)
322 319 {
323 320 rio_store_t *rsp;
324 321 rio_store_t *new_rsp;
325 322 list_t *listp;
326 323 char *new_path;
327 324
328 325 STORE_DBG((CE_NOTE, "e_ddi_retire_persist: entered: %s", devpath));
329 326
330 327 new_rsp = kmem_zalloc(sizeof (*new_rsp), KM_SLEEP);
331 328 new_rsp->rst_devpath = new_path = i_ddi_strdup(devpath, KM_SLEEP);
332 329 new_rsp->rst_flags = RIO_STORE_F_RETIRED;
333 330
334 331 rw_enter(nvf_lock(rio_store_handle), RW_WRITER);
335 332
336 333 listp = nvf_list(rio_store_handle);
337 334 for (rsp = list_head(listp); rsp; rsp = list_next(listp, rsp)) {
338 335 int flag_mask = RIO_STORE_F_RETIRED|RIO_STORE_F_BYPASS;
339 336 ASSERT(!(rsp->rst_flags & ~flag_mask));
340 337
341 338 /* already there */
342 339 if (strcmp(devpath, rsp->rst_devpath) == 0) {
343 340 /* explicit retire, clear bypass flag (if any) */
344 341 rsp->rst_flags &= ~RIO_STORE_F_BYPASS;
345 342 ASSERT(rsp->rst_flags == RIO_STORE_F_RETIRED);
346 343 rw_exit(nvf_lock(rio_store_handle));
347 344 kmem_free(new_path, strlen(new_path) + 1);
348 345 kmem_free(new_rsp, sizeof (*new_rsp));
349 346 STORE_DBG((CE_NOTE, "store: already in. Clear bypass "
350 347 ": %s", devpath));
351 348 return (0);
352 349 }
353 350
354 351 }
355 352
356 353 ASSERT(rsp == NULL);
357 354 list_insert_tail(listp, new_rsp);
358 355
359 356 nvf_mark_dirty(rio_store_handle);
360 357
361 358 rw_exit(nvf_lock(rio_store_handle));
362 359
363 360 nvf_wake_daemon();
364 361
365 362 STORE_DBG((CE_NOTE, "store: New, added to list, dirty: %s", devpath));
366 363
367 364 return (0);
368 365 }
369 366
370 367 int
371 368 e_ddi_retire_unpersist(char *devpath)
372 369 {
373 370 rio_store_t *rsp;
374 371 rio_store_t *next;
375 372 list_t *listp;
376 373 int is_dirty = 0;
377 374
378 375 STORE_DBG((CE_NOTE, "e_ddi_retire_unpersist: entered: %s", devpath));
379 376
380 377 rw_enter(nvf_lock(rio_store_handle), RW_WRITER);
381 378
382 379 listp = nvf_list(rio_store_handle);
383 380 for (rsp = list_head(listp); rsp; rsp = next) {
384 381 next = list_next(listp, rsp);
385 382 if (strcmp(devpath, rsp->rst_devpath) != 0)
386 383 continue;
387 384
388 385 list_remove(listp, rsp);
389 386 rio_store_free(rsp);
390 387
391 388 STORE_DBG((CE_NOTE, "store: found in list. Freed: %s",
392 389 devpath));
393 390
394 391 nvf_mark_dirty(rio_store_handle);
395 392 is_dirty = 1;
396 393 }
397 394
398 395 rw_exit(nvf_lock(rio_store_handle));
399 396
400 397 if (is_dirty)
401 398 nvf_wake_daemon();
402 399
403 400 return (is_dirty);
404 401 }
405 402
406 403 int
407 404 e_ddi_device_retired(char *devpath)
408 405 {
409 406 list_t *listp;
410 407 rio_store_t *rsp;
411 408 size_t len;
412 409 int retired;
413 410
414 411 retired = 0;
415 412
416 413 rw_enter(nvf_lock(rio_store_handle), RW_READER);
417 414
418 415 listp = nvf_list(rio_store_handle);
419 416 for (rsp = list_head(listp); rsp; rsp = list_next(listp, rsp)) {
420 417 int flag_mask = RIO_STORE_F_RETIRED|RIO_STORE_F_BYPASS;
421 418 ASSERT(!(rsp->rst_flags & ~flag_mask));
422 419
423 420 /*
424 421 * If the "bypass" flag is set, then the device
425 422 * is *not* retired for the current boot of the
426 423 * system. It indicates that the retire store
427 424 * was read but the devices in the retire store
428 425 * were not retired i.e. effectively the store
429 426 * was bypassed. For why we bother to even read
430 427 * the store when we bypass it, see the comments
431 428 * for the tunable ddi_retire_store_bypass.
432 429 */
433 430 if (rsp->rst_flags & RIO_STORE_F_BYPASS) {
434 431 STORE_TRC((CE_NOTE, "store: found & bypassed: %s",
435 432 rsp->rst_devpath));
436 433 continue;
437 434 }
438 435
439 436 /*
440 437 * device is retired, if it or a parent exists
441 438 * in the in-core list
442 439 */
443 440 len = strlen(rsp->rst_devpath);
444 441 if (strncmp(devpath, rsp->rst_devpath, len) != 0)
445 442 continue;
446 443 if (devpath[len] == '\0' || devpath[len] == '/') {
447 444 /* exact match or a child */
448 445 retired = 1;
449 446 STORE_TRC((CE_NOTE, "store: found & !bypassed: %s",
450 447 devpath));
451 448 break;
452 449 }
453 450 }
454 451 rw_exit(nvf_lock(rio_store_handle));
455 452
456 453 return (retired);
457 454 }
↓ open down ↓ |
133 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX