Print this page
2976 remove useless offsetof() macros
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/stat/common/acquire_iodevs.c
+++ new/usr/src/cmd/stat/common/acquire_iodevs.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
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 /*
↓ open down ↓ |
21 lines elided |
↑ open up ↑ |
22 22 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
23 23 */
24 24
25 25 #include "statcommon.h"
26 26 #include "dsr.h"
27 27
28 28 #include <sys/dklabel.h>
29 29 #include <sys/dktp/fdisk.h>
30 30 #include <stdlib.h>
31 31 #include <stdarg.h>
32 +#include <stddef.h>
32 33 #include <unistd.h>
33 34 #include <strings.h>
34 35 #include <errno.h>
35 36 #include <limits.h>
36 37
37 38 static void insert_iodev(struct snapshot *ss, struct iodev_snapshot *iodev);
38 39
39 40 static struct iodev_snapshot *
40 41 make_controller(int cid)
41 42 {
42 43 struct iodev_snapshot *new;
43 44
44 45 new = safe_alloc(sizeof (struct iodev_snapshot));
45 46 (void) memset(new, 0, sizeof (struct iodev_snapshot));
46 47 new->is_type = IODEV_CONTROLLER;
47 48 new->is_id.id = cid;
48 49 new->is_parent_id.id = IODEV_NO_ID;
49 50
50 51 (void) snprintf(new->is_name, sizeof (new->is_name), "c%d", cid);
51 52
52 53 return (new);
53 54 }
54 55
55 56 static struct iodev_snapshot *
56 57 find_iodev_by_name(struct iodev_snapshot *list, const char *name)
57 58 {
58 59 struct iodev_snapshot *pos;
59 60 struct iodev_snapshot *pos2;
60 61
61 62 for (pos = list; pos; pos = pos->is_next) {
62 63 if (strcmp(pos->is_name, name) == 0)
63 64 return (pos);
64 65
65 66 pos2 = find_iodev_by_name(pos->is_children, name);
66 67 if (pos2 != NULL)
67 68 return (pos2);
68 69 }
69 70
70 71 return (NULL);
71 72 }
72 73
73 74 static enum iodev_type
74 75 parent_iodev_type(enum iodev_type type)
75 76 {
76 77 switch (type) {
77 78 case IODEV_CONTROLLER: return (0);
78 79 case IODEV_IOPATH_LT: return (0);
79 80 case IODEV_IOPATH_LI: return (0);
80 81 case IODEV_NFS: return (0);
81 82 case IODEV_TAPE: return (0);
82 83 case IODEV_IOPATH_LTI: return (IODEV_DISK);
83 84 case IODEV_DISK: return (IODEV_CONTROLLER);
84 85 case IODEV_PARTITION: return (IODEV_DISK);
85 86 }
86 87 return (IODEV_UNKNOWN);
87 88 }
88 89
89 90 static int
90 91 id_match(struct iodev_id *id1, struct iodev_id *id2)
91 92 {
92 93 return (id1->id == id2->id &&
93 94 strcmp(id1->tid, id2->tid) == 0);
94 95 }
95 96
96 97 static struct iodev_snapshot *
97 98 find_parent(struct snapshot *ss, struct iodev_snapshot *iodev)
98 99 {
99 100 enum iodev_type parent_type = parent_iodev_type(iodev->is_type);
100 101 struct iodev_snapshot *pos;
101 102 struct iodev_snapshot *pos2;
102 103
103 104 if (parent_type == 0 || parent_type == IODEV_UNKNOWN)
104 105 return (NULL);
105 106
106 107 if (iodev->is_parent_id.id == IODEV_NO_ID &&
107 108 iodev->is_parent_id.tid[0] == '\0')
108 109 return (NULL);
109 110
110 111 if (parent_type == IODEV_CONTROLLER) {
111 112 for (pos = ss->s_iodevs; pos; pos = pos->is_next) {
112 113 if (pos->is_type != IODEV_CONTROLLER)
113 114 continue;
114 115 if (pos->is_id.id != iodev->is_parent_id.id)
115 116 continue;
116 117 return (pos);
117 118 }
118 119
119 120 if (!(ss->s_types & SNAP_CONTROLLERS))
120 121 return (NULL);
121 122
122 123 pos = make_controller(iodev->is_parent_id.id);
123 124 insert_iodev(ss, pos);
124 125 return (pos);
125 126 }
126 127
127 128 /* IODEV_DISK parent */
128 129 for (pos = ss->s_iodevs; pos; pos = pos->is_next) {
129 130 if (id_match(&iodev->is_parent_id, &pos->is_id) &&
130 131 pos->is_type == IODEV_DISK)
131 132 return (pos);
132 133 if (pos->is_type != IODEV_CONTROLLER)
133 134 continue;
134 135 for (pos2 = pos->is_children; pos2; pos2 = pos2->is_next) {
135 136 if (pos2->is_type != IODEV_DISK)
136 137 continue;
137 138 if (id_match(&iodev->is_parent_id, &pos2->is_id))
138 139 return (pos2);
139 140 }
↓ open down ↓ |
98 lines elided |
↑ open up ↑ |
140 141 }
141 142
142 143 return (NULL);
143 144 }
144 145
145 146 /*
146 147 * Introduce an index into the list to speed up insert_into looking for the
147 148 * right position in the list. This index is an AVL tree of all the
148 149 * iodev_snapshot in the list.
149 150 */
150 -
151 -#define offsetof(s, m) (size_t)(&(((s *)0)->m)) /* for avl_create */
152 -
153 151 static int
154 152 avl_iodev_cmp(const void* is1, const void* is2)
155 153 {
156 154 int c = iodev_cmp((struct iodev_snapshot *)is1,
157 155 (struct iodev_snapshot *)is2);
158 156
159 157 if (c > 0)
160 158 return (1);
161 159
162 160 if (c < 0)
163 161 return (-1);
164 162
165 163 return (0);
166 164 }
167 165
168 166 static void
169 167 ix_new_list(struct iodev_snapshot *elem)
170 168 {
171 169 avl_tree_t *l = malloc(sizeof (avl_tree_t));
172 170
173 171 elem->avl_list = l;
174 172 if (l == NULL)
175 173 return;
176 174
177 175 avl_create(l, avl_iodev_cmp, sizeof (struct iodev_snapshot),
178 176 offsetof(struct iodev_snapshot, avl_link));
179 177
180 178 avl_add(l, elem);
181 179 }
182 180
183 181 static void
184 182 ix_list_del(struct iodev_snapshot *elem)
185 183 {
186 184 avl_tree_t *l = elem->avl_list;
187 185
188 186 if (l == NULL)
189 187 return;
190 188
191 189 elem->avl_list = NULL;
192 190
193 191 avl_remove(l, elem);
194 192 if (avl_numnodes(l) == 0) {
195 193 avl_destroy(l);
196 194 free(l);
197 195 }
198 196 }
199 197
200 198 static void
201 199 ix_insert_here(struct iodev_snapshot *pos, struct iodev_snapshot *elem, int ba)
202 200 {
203 201 avl_tree_t *l = pos->avl_list;
204 202 elem->avl_list = l;
205 203
206 204 if (l == NULL)
207 205 return;
208 206
209 207 avl_insert_here(l, elem, pos, ba);
210 208 }
211 209
212 210 static void
213 211 list_del(struct iodev_snapshot **list, struct iodev_snapshot *pos)
214 212 {
215 213 ix_list_del(pos);
216 214
217 215 if (*list == pos)
218 216 *list = pos->is_next;
219 217 if (pos->is_next)
220 218 pos->is_next->is_prev = pos->is_prev;
221 219 if (pos->is_prev)
222 220 pos->is_prev->is_next = pos->is_next;
223 221 pos->is_prev = pos->is_next = NULL;
224 222 }
225 223
226 224 static void
227 225 insert_before(struct iodev_snapshot **list, struct iodev_snapshot *pos,
228 226 struct iodev_snapshot *new)
229 227 {
230 228 if (pos == NULL) {
231 229 new->is_prev = new->is_next = NULL;
232 230 *list = new;
233 231 ix_new_list(new);
234 232 return;
235 233 }
236 234
237 235 new->is_next = pos;
238 236 new->is_prev = pos->is_prev;
239 237 if (pos->is_prev)
240 238 pos->is_prev->is_next = new;
241 239 else
242 240 *list = new;
243 241 pos->is_prev = new;
244 242
245 243 ix_insert_here(pos, new, AVL_BEFORE);
246 244 }
247 245
248 246 static void
249 247 insert_after(struct iodev_snapshot **list, struct iodev_snapshot *pos,
250 248 struct iodev_snapshot *new)
251 249 {
252 250 if (pos == NULL) {
253 251 new->is_prev = new->is_next = NULL;
254 252 *list = new;
255 253 ix_new_list(new);
256 254 return;
257 255 }
258 256
259 257 new->is_next = pos->is_next;
260 258 new->is_prev = pos;
261 259 if (pos->is_next)
262 260 pos->is_next->is_prev = new;
263 261 pos->is_next = new;
264 262
265 263 ix_insert_here(pos, new, AVL_AFTER);
266 264 }
267 265
268 266 static void
269 267 insert_into(struct iodev_snapshot **list, struct iodev_snapshot *iodev)
270 268 {
271 269 struct iodev_snapshot *tmp = *list;
272 270 avl_tree_t *l;
273 271 void *p;
274 272 avl_index_t where;
275 273
276 274 if (*list == NULL) {
277 275 *list = iodev;
278 276 ix_new_list(iodev);
279 277 return;
280 278 }
281 279
282 280 /*
283 281 * Optimize the search: instead of walking the entire list
284 282 * (which can contain thousands of nodes), search in the AVL
285 283 * tree the nearest node and reposition the startup point to
286 284 * this node rather than always starting from the beginning
287 285 * of the list.
288 286 */
289 287 l = tmp->avl_list;
290 288 if (l != NULL) {
291 289 p = avl_find(l, iodev, &where);
292 290 if (p == NULL) {
293 291 p = avl_nearest(l, where, AVL_BEFORE);
294 292 }
295 293 if (p != NULL) {
296 294 tmp = (struct iodev_snapshot *)p;
297 295 }
298 296 }
299 297
300 298 for (;;) {
301 299 if (iodev_cmp(tmp, iodev) > 0) {
302 300 insert_before(list, tmp, iodev);
303 301 return;
304 302 }
305 303
306 304 if (tmp->is_next == NULL)
307 305 break;
308 306
309 307 tmp = tmp->is_next;
310 308 }
311 309
312 310 insert_after(list, tmp, iodev);
313 311 }
314 312
315 313 static int
316 314 disk_or_partition(enum iodev_type type)
317 315 {
318 316 return (type == IODEV_DISK || type == IODEV_PARTITION);
319 317 }
320 318
321 319 static int
322 320 disk_or_partition_or_iopath(enum iodev_type type)
323 321 {
324 322 return (type == IODEV_DISK || type == IODEV_PARTITION ||
325 323 type == IODEV_IOPATH_LTI);
326 324 }
327 325
328 326 static void
329 327 insert_iodev(struct snapshot *ss, struct iodev_snapshot *iodev)
330 328 {
331 329 struct iodev_snapshot *parent = find_parent(ss, iodev);
332 330 struct iodev_snapshot **list;
333 331
334 332 if (parent != NULL) {
335 333 list = &parent->is_children;
336 334 parent->is_nr_children++;
337 335 } else {
338 336 list = &ss->s_iodevs;
339 337 ss->s_nr_iodevs++;
340 338 }
341 339
342 340 insert_into(list, iodev);
343 341 }
344 342
345 343 /* return 1 if dev passes filter */
346 344 static int
347 345 iodev_match(struct iodev_snapshot *dev, struct iodev_filter *df)
348 346 {
349 347 int is_floppy = (strncmp(dev->is_name, "fd", 2) == 0);
350 348 char *isn, *ispn, *ifn;
351 349 char *path;
352 350 int ifnl;
353 351 size_t i;
354 352
355 353 /* no filter, pass */
356 354 if (df == NULL)
357 355 return (1); /* pass */
358 356
359 357 /* no filtered names, pass if not floppy and skipped */
360 358 if (df->if_nr_names == NULL)
361 359 return (!(df->if_skip_floppy && is_floppy));
362 360
363 361 isn = dev->is_name;
364 362 ispn = dev->is_pretty;
365 363 for (i = 0; i < df->if_nr_names; i++) {
366 364 ifn = df->if_names[i];
367 365 ifnl = strlen(ifn);
368 366 path = strchr(ifn, '.');
369 367
370 368 if ((strcmp(isn, ifn) == 0) ||
371 369 (ispn && (strcmp(ispn, ifn) == 0)))
372 370 return (1); /* pass */
373 371
374 372 /* if filter is a path allow partial match */
375 373 if (path &&
376 374 ((strncmp(isn, ifn, ifnl) == 0) ||
377 375 (ispn && (strncmp(ispn, ifn, ifnl) == 0))))
378 376 return (1); /* pass */
379 377 }
380 378
381 379 return (0); /* fail */
382 380 }
383 381
384 382 /* return 1 if path is an mpxio path associated with dev */
385 383 static int
386 384 iodev_path_match(struct iodev_snapshot *dev, struct iodev_snapshot *path)
387 385 {
388 386 char *dn, *pn;
389 387 int dnl;
390 388
391 389 dn = dev->is_name;
392 390 pn = path->is_name;
393 391 dnl = strlen(dn);
394 392
395 393 if ((strncmp(pn, dn, dnl) == 0) && (pn[dnl] == '.'))
396 394 return (1); /* yes */
397 395
398 396 return (0); /* no */
399 397 }
400 398
401 399 /* select which I/O devices to collect stats for */
402 400 static void
403 401 choose_iodevs(struct snapshot *ss, struct iodev_snapshot *iodevs,
404 402 struct iodev_filter *df)
405 403 {
406 404 struct iodev_snapshot *pos, *ppos, *tmp, *ptmp;
407 405 int nr_iodevs;
408 406 int nr_iodevs_orig;
409 407
410 408 nr_iodevs = df ? df->if_max_iodevs : UNLIMITED_IODEVS;
411 409 nr_iodevs_orig = nr_iodevs;
412 410
413 411 if (nr_iodevs == UNLIMITED_IODEVS)
414 412 nr_iodevs = INT_MAX;
415 413
416 414 /* add the full matches */
417 415 pos = iodevs;
418 416 while (pos && nr_iodevs) {
419 417 tmp = pos;
420 418 pos = pos->is_next;
421 419
422 420 if (!iodev_match(tmp, df))
423 421 continue; /* failed full match */
424 422
425 423 list_del(&iodevs, tmp);
426 424 insert_iodev(ss, tmp);
427 425
428 426 /*
429 427 * Add all mpxio paths associated with match above. Added
430 428 * paths don't count against nr_iodevs.
431 429 */
432 430 if (strchr(tmp->is_name, '.') == NULL) {
433 431 ppos = iodevs;
434 432 while (ppos) {
435 433 ptmp = ppos;
436 434 ppos = ppos->is_next;
437 435
438 436 if (!iodev_path_match(tmp, ptmp))
439 437 continue; /* not an mpxio path */
440 438
441 439 list_del(&iodevs, ptmp);
442 440 insert_iodev(ss, ptmp);
443 441 if (pos == ptmp)
444 442 pos = ppos;
445 443 }
446 444 }
447 445
448 446 nr_iodevs--;
449 447 }
450 448
451 449 /*
452 450 * If we had a filter, and *nothing* passed the filter then we
453 451 * don't want to fill the remaining slots - it is just confusing
454 452 * if we don that, it makes it look like the filter code is broken.
455 453 */
456 454 if ((df->if_nr_names == NULL) || (nr_iodevs != nr_iodevs_orig)) {
457 455 /* now insert any iodevs into the remaining slots */
458 456 pos = iodevs;
459 457 while (pos && nr_iodevs) {
460 458 tmp = pos;
461 459 pos = pos->is_next;
462 460
463 461 if (df && df->if_skip_floppy &&
464 462 strncmp(tmp->is_name, "fd", 2) == 0)
465 463 continue;
466 464
467 465 list_del(&iodevs, tmp);
468 466 insert_iodev(ss, tmp);
469 467
470 468 --nr_iodevs;
471 469 }
472 470 }
473 471
474 472 /* clear the unwanted ones */
475 473 pos = iodevs;
476 474 while (pos) {
477 475 struct iodev_snapshot *tmp = pos;
478 476 pos = pos->is_next;
479 477 free_iodev(tmp);
480 478 }
481 479 }
482 480
483 481 static int
484 482 collate_controller(struct iodev_snapshot *controller,
485 483 struct iodev_snapshot *disk)
486 484 {
487 485 controller->is_stats.nread += disk->is_stats.nread;
488 486 controller->is_stats.nwritten += disk->is_stats.nwritten;
489 487 controller->is_stats.reads += disk->is_stats.reads;
490 488 controller->is_stats.writes += disk->is_stats.writes;
491 489 controller->is_stats.wtime += disk->is_stats.wtime;
492 490 controller->is_stats.wlentime += disk->is_stats.wlentime;
493 491 controller->is_stats.rtime += disk->is_stats.rtime;
494 492 controller->is_stats.rlentime += disk->is_stats.rlentime;
495 493 controller->is_crtime += disk->is_crtime;
496 494 controller->is_snaptime += disk->is_snaptime;
497 495 if (kstat_add(&disk->is_errors, &controller->is_errors))
498 496 return (errno);
499 497 return (0);
500 498 }
501 499
502 500 static int
503 501 acquire_iodev_stats(struct iodev_snapshot *list, kstat_ctl_t *kc)
504 502 {
505 503 struct iodev_snapshot *pos;
506 504 int err = 0;
507 505
508 506 for (pos = list; pos; pos = pos->is_next) {
509 507 /* controllers don't have stats (yet) */
510 508 if (pos->is_ksp != NULL) {
511 509 if (kstat_read(kc, pos->is_ksp, &pos->is_stats) == -1)
512 510 return (errno);
513 511 /* make sure crtime/snaptime is updated */
514 512 pos->is_crtime = pos->is_ksp->ks_crtime;
515 513 pos->is_snaptime = pos->is_ksp->ks_snaptime;
516 514 }
517 515
518 516 if ((err = acquire_iodev_stats(pos->is_children, kc)))
519 517 return (err);
520 518
521 519 if (pos->is_type == IODEV_CONTROLLER) {
522 520 struct iodev_snapshot *pos2 = pos->is_children;
523 521
524 522 for (; pos2; pos2 = pos2->is_next) {
525 523 if ((err = collate_controller(pos, pos2)))
526 524 return (err);
527 525 }
528 526 }
529 527 }
530 528
531 529 return (0);
532 530 }
533 531
534 532 static int
535 533 acquire_iodev_errors(struct snapshot *ss, kstat_ctl_t *kc)
536 534 {
537 535 kstat_t *ksp;
538 536
539 537 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
540 538 char kstat_name[KSTAT_STRLEN];
541 539 char *dname = kstat_name;
542 540 char *ename = ksp->ks_name;
543 541 struct iodev_snapshot *iodev;
544 542
545 543 if (ksp->ks_type != KSTAT_TYPE_NAMED)
546 544 continue;
547 545 if (strncmp(ksp->ks_class, "device_error", 12) != 0 &&
548 546 strncmp(ksp->ks_class, "iopath_error", 12) != 0)
549 547 continue;
550 548
551 549 /*
552 550 * Some drivers may not follow the naming convention
553 551 * for error kstats (i.e., drivername,err) so
554 552 * be sure we don't walk off the end.
555 553 */
556 554 while (*ename && *ename != ',') {
557 555 *dname = *ename;
558 556 dname++;
559 557 ename++;
560 558 }
561 559 *dname = '\0';
562 560
563 561 iodev = find_iodev_by_name(ss->s_iodevs, kstat_name);
564 562
565 563 if (iodev == NULL)
566 564 continue;
567 565
568 566 if (kstat_read(kc, ksp, NULL) == -1)
569 567 return (errno);
570 568 if (kstat_copy(ksp, &iodev->is_errors) == -1)
571 569 return (errno);
572 570 }
573 571
574 572 return (0);
575 573 }
576 574
577 575 static void
578 576 get_ids(struct iodev_snapshot *iodev, const char *pretty)
579 577 {
580 578 int ctr, disk, slice, ret;
581 579 char *target;
582 580 const char *p1;
583 581 const char *p2;
584 582
585 583 if (pretty == NULL)
586 584 return;
587 585
588 586 if (sscanf(pretty, "c%d", &ctr) != 1)
589 587 return;
590 588
591 589 p1 = pretty;
592 590 while (*p1 && *p1 != 't')
593 591 ++p1;
594 592
595 593 if (!*p1)
596 594 return;
597 595 ++p1;
598 596
599 597 p2 = p1;
600 598 while (*p2 && *p2 != 'd')
601 599 ++p2;
602 600
603 601 if (!*p2 || p2 == p1)
604 602 return;
605 603
606 604 target = safe_alloc(1 + p2 - p1);
607 605 (void) strlcpy(target, p1, 1 + p2 - p1);
608 606
609 607 ret = sscanf(p2, "d%d%*[sp]%d", &disk, &slice);
610 608
611 609 if (ret == 2 && iodev->is_type == IODEV_PARTITION) {
612 610 iodev->is_id.id = slice;
613 611 iodev->is_parent_id.id = disk;
614 612 (void) strlcpy(iodev->is_parent_id.tid, target, KSTAT_STRLEN);
615 613 } else if (ret == 1) {
616 614 if (iodev->is_type == IODEV_DISK) {
617 615 iodev->is_id.id = disk;
618 616 (void) strlcpy(iodev->is_id.tid, target, KSTAT_STRLEN);
619 617 iodev->is_parent_id.id = ctr;
620 618 } else if (iodev->is_type == IODEV_IOPATH_LTI) {
621 619 iodev->is_parent_id.id = disk;
622 620 (void) strlcpy(iodev->is_parent_id.tid,
623 621 target, KSTAT_STRLEN);
624 622 }
625 623 }
626 624
627 625 free(target);
628 626 }
629 627
630 628 static void
631 629 get_pretty_name(enum snapshot_types types, struct iodev_snapshot *iodev,
632 630 kstat_ctl_t *kc)
633 631 {
634 632 disk_list_t *dl;
635 633 char *pretty = NULL;
636 634
637 635 if (iodev->is_type == IODEV_NFS) {
638 636 if (!(types & SNAP_IODEV_PRETTY))
639 637 return;
640 638
641 639 iodev->is_pretty = lookup_nfs_name(iodev->is_name, kc);
642 640 return;
643 641 }
644 642
645 643 /* lookup/translate the kstat name */
646 644 dl = lookup_ks_name(iodev->is_name, (types & SNAP_IODEV_DEVID) ? 1 : 0);
647 645 if (dl == NULL)
648 646 return;
649 647
650 648 if (dl->dsk)
651 649 pretty = safe_strdup(dl->dsk);
652 650
653 651 if (types & SNAP_IODEV_PRETTY) {
654 652 if (dl->dname)
655 653 iodev->is_dname = safe_strdup(dl->dname);
656 654 }
657 655
658 656 if (dl->devidstr)
659 657 iodev->is_devid = safe_strdup(dl->devidstr);
660 658
661 659 get_ids(iodev, pretty);
662 660
663 661 /*
664 662 * we fill in pretty name wether it is asked for or not because
665 663 * it could be used in a filter by match_iodevs.
666 664 */
667 665 iodev->is_pretty = pretty;
668 666 }
669 667
670 668 static enum iodev_type
671 669 get_iodev_type(kstat_t *ksp)
672 670 {
673 671 if (strcmp(ksp->ks_class, "disk") == 0)
674 672 return (IODEV_DISK);
675 673 if (strcmp(ksp->ks_class, "partition") == 0)
676 674 return (IODEV_PARTITION);
677 675 if (strcmp(ksp->ks_class, "nfs") == 0)
678 676 return (IODEV_NFS);
679 677 if (strcmp(ksp->ks_class, "iopath") == 0)
680 678 return (IODEV_IOPATH_LTI);
681 679 if (strcmp(ksp->ks_class, "tape") == 0)
682 680 return (IODEV_TAPE);
683 681 return (IODEV_UNKNOWN);
684 682 }
685 683
686 684 /* get the lun/target/initiator from the name, return 1 on success */
687 685 static int
688 686 get_lti(char *s,
689 687 char *lname, int *l, char *tname, int *t, char *iname, int *i)
690 688 {
691 689 int num = 0;
692 690
693 691 num = sscanf(s, "%[a-z]%d%*[.]%[a-z]%d%*[.]%[a-z_]%d", lname, l,
694 692 tname, t, iname, i);
695 693 return ((num == 6) ? 1 : 0);
696 694 }
697 695
698 696
699 697 /* get the lun, target, and initiator name and instance */
700 698 static void
701 699 get_path_info(struct iodev_snapshot *io, char *mod, size_t modlen, int *type,
702 700 int *inst, char *name, size_t size)
703 701 {
704 702
705 703 /*
706 704 * If it is iopath or ssd then pad the name with i/t/l so we can sort
707 705 * by alpha order and set type for IOPATH to DISK since we want to
708 706 * have it grouped with its ssd parent. The lun can be 5 digits,
709 707 * the target can be 4 digits, and the initiator can be 3 digits and
710 708 * the padding is done appropriately for string comparisons.
711 709 */
712 710 if (disk_or_partition_or_iopath(io->is_type)) {
713 711 int i1, t1, l1;
714 712 char tname[KSTAT_STRLEN], iname[KSTAT_STRLEN];
715 713 char *ptr, lname[KSTAT_STRLEN];
716 714
717 715 i1 = t1 = l1 = 0;
718 716 (void) get_lti(io->is_name, lname, &l1, tname, &t1, iname, &i1);
719 717 *type = io->is_type;
720 718 if (io->is_type == IODEV_DISK) {
721 719 (void) snprintf(name, size, "%s%05d", lname, l1);
722 720 } else if (io->is_type == IODEV_PARTITION) {
723 721 ptr = strchr(io->is_name, ',');
724 722 (void) snprintf(name, size, "%s%05d%s", lname, l1, ptr);
725 723 } else {
726 724 (void) snprintf(name, size, "%s%05d.%s%04d.%s%03d",
727 725 lname, l1, tname, t1, iname, i1);
728 726 /* set to disk so we sort with disks */
729 727 *type = IODEV_DISK;
730 728 }
731 729 (void) strlcpy(mod, lname, modlen);
732 730 *inst = l1;
733 731 } else {
734 732 (void) strlcpy(mod, io->is_module, modlen);
735 733 (void) strlcpy(name, io->is_name, size);
736 734 *type = io->is_type;
737 735 *inst = io->is_instance;
738 736 }
739 737 }
740 738
741 739 int
742 740 iodev_cmp(struct iodev_snapshot *io1, struct iodev_snapshot *io2)
743 741 {
744 742 int type1, type2;
745 743 int inst1, inst2;
746 744 char name1[KSTAT_STRLEN], name2[KSTAT_STRLEN];
747 745 char mod1[KSTAT_STRLEN], mod2[KSTAT_STRLEN];
748 746
749 747 get_path_info(io1, mod1, sizeof (mod1), &type1, &inst1, name1,
750 748 sizeof (name1));
751 749 get_path_info(io2, mod2, sizeof (mod2), &type2, &inst2, name2,
752 750 sizeof (name2));
753 751 if ((!disk_or_partition(type1)) ||
754 752 (!disk_or_partition(type2))) {
755 753 /* neutral sort order between disk and part */
756 754 if (type1 < type2) {
757 755 return (-1);
758 756 }
759 757 if (type1 > type2) {
760 758 return (1);
761 759 }
762 760 }
763 761
764 762 /* controller doesn't have ksp */
765 763 if (io1->is_ksp && io2->is_ksp) {
766 764 if (strcmp(mod1, mod2) != 0) {
767 765 return (strcmp(mod1, mod2));
768 766 }
769 767 if (inst1 < inst2) {
770 768 return (-1);
771 769 }
772 770 if (inst1 > inst2) {
773 771 return (1);
774 772 }
775 773 } else {
776 774 if (io1->is_id.id < io2->is_id.id) {
777 775 return (-1);
778 776 }
779 777 if (io1->is_id.id > io2->is_id.id) {
780 778 return (1);
781 779 }
782 780 }
783 781
784 782 return (strcmp(name1, name2));
785 783 }
786 784
787 785 /* update the target reads and writes */
788 786 static void
789 787 update_target(struct iodev_snapshot *tgt, struct iodev_snapshot *path)
790 788 {
791 789 tgt->is_stats.reads += path->is_stats.reads;
792 790 tgt->is_stats.writes += path->is_stats.writes;
793 791 tgt->is_stats.nread += path->is_stats.nread;
794 792 tgt->is_stats.nwritten += path->is_stats.nwritten;
795 793 tgt->is_stats.wcnt += path->is_stats.wcnt;
796 794 tgt->is_stats.rcnt += path->is_stats.rcnt;
797 795
798 796 /*
799 797 * Stash the t_delta in the crtime for use in show_disk
800 798 * NOTE: this can't be done in show_disk because the
801 799 * itl entry is removed for the old format
802 800 */
803 801 tgt->is_crtime += hrtime_delta(path->is_crtime, path->is_snaptime);
804 802 tgt->is_snaptime += path->is_snaptime;
805 803 tgt->is_nr_children += 1;
806 804 }
807 805
808 806 /*
809 807 * Create a new synthetic device entry of the specified type. The supported
810 808 * synthetic types are IODEV_IOPATH_LT and IODEV_IOPATH_LI.
811 809 */
812 810 static struct iodev_snapshot *
813 811 make_extended_device(int type, struct iodev_snapshot *old)
814 812 {
815 813 struct iodev_snapshot *tptr = NULL;
816 814 char *ptr;
817 815 int lun, tgt, initiator;
818 816 char lun_name[KSTAT_STRLEN];
819 817 char tgt_name[KSTAT_STRLEN];
820 818 char initiator_name[KSTAT_STRLEN];
821 819
822 820 if (old == NULL)
823 821 return (NULL);
824 822 if (get_lti(old->is_name,
825 823 lun_name, &lun, tgt_name, &tgt, initiator_name, &initiator) != 1) {
826 824 return (NULL);
827 825 }
828 826 tptr = safe_alloc(sizeof (*old));
829 827 bzero(tptr, sizeof (*old));
830 828 if (old->is_pretty != NULL) {
831 829 tptr->is_pretty = safe_alloc(strlen(old->is_pretty) + 1);
832 830 (void) strcpy(tptr->is_pretty, old->is_pretty);
833 831 }
834 832 bcopy(&old->is_parent_id, &tptr->is_parent_id,
835 833 sizeof (old->is_parent_id));
836 834
837 835 tptr->is_type = type;
838 836
839 837 if (type == IODEV_IOPATH_LT) {
840 838 /* make new synthetic entry that is the LT */
841 839 /* set the id to the target id */
842 840 tptr->is_id.id = tgt;
843 841 (void) snprintf(tptr->is_id.tid, sizeof (tptr->is_id.tid),
844 842 "%s%d", tgt_name, tgt);
845 843 (void) snprintf(tptr->is_name, sizeof (tptr->is_name),
846 844 "%s%d.%s%d", lun_name, lun, tgt_name, tgt);
847 845
848 846 if (old->is_pretty) {
849 847 ptr = strrchr(tptr->is_pretty, '.');
850 848 if (ptr)
851 849 *ptr = '\0';
852 850 }
853 851 } else if (type == IODEV_IOPATH_LI) {
854 852 /* make new synthetic entry that is the LI */
855 853 /* set the id to the initiator number */
856 854 tptr->is_id.id = initiator;
857 855 (void) snprintf(tptr->is_id.tid, sizeof (tptr->is_id.tid),
858 856 "%s%d", initiator_name, initiator);
859 857 (void) snprintf(tptr->is_name, sizeof (tptr->is_name),
860 858 "%s%d.%s%d", lun_name, lun, initiator_name, initiator);
861 859
862 860 if (old->is_pretty) {
863 861 ptr = strchr(tptr->is_pretty, '.');
864 862 if (ptr)
865 863 (void) snprintf(ptr + 1,
866 864 strlen(tptr->is_pretty) + 1,
867 865 "%s%d", initiator_name, initiator);
868 866 }
869 867 }
870 868 return (tptr);
871 869 }
872 870
873 871 /*
874 872 * This is to get the original -X LI format (e.g. ssd1.fp0). When an LTI kstat
875 873 * is found - traverse the children looking for the same initiator and sum
876 874 * them up. Add an LI entry and delete all of the LTI entries with the same
877 875 * initiator.
878 876 */
879 877 static int
880 878 create_li_delete_lti(struct snapshot *ss, struct iodev_snapshot *list)
881 879 {
882 880 struct iodev_snapshot *pos, *entry, *parent;
883 881 int lun, tgt, initiator;
884 882 char lun_name[KSTAT_STRLEN];
885 883 char tgt_name[KSTAT_STRLEN];
886 884 char initiator_name[KSTAT_STRLEN];
887 885 int err;
888 886
889 887 for (entry = list; entry; entry = entry->is_next) {
890 888 if ((err = create_li_delete_lti(ss, entry->is_children)) != 0)
891 889 return (err);
892 890
893 891 if (entry->is_type == IODEV_IOPATH_LTI) {
894 892 parent = find_parent(ss, entry);
895 893 if (get_lti(entry->is_name, lun_name, &lun,
896 894 tgt_name, &tgt, initiator_name, &initiator) != 1) {
897 895 return (1);
898 896 }
899 897
900 898 pos = (parent == NULL) ? NULL : parent->is_children;
901 899 for (; pos; pos = pos->is_next) {
902 900 if (pos->is_id.id != -1 &&
903 901 pos->is_id.id == initiator &&
904 902 pos->is_type == IODEV_IOPATH_LI) {
905 903 /* found the same initiator */
906 904 update_target(pos, entry);
907 905 list_del(&parent->is_children, entry);
908 906 free_iodev(entry);
909 907 parent->is_nr_children--;
910 908 entry = pos;
911 909 break;
912 910 }
913 911 }
914 912
915 913 if (!pos) {
916 914 /* make the first LI entry */
917 915 pos = make_extended_device(
918 916 IODEV_IOPATH_LI, entry);
919 917 update_target(pos, entry);
920 918
921 919 if (parent) {
922 920 insert_before(&parent->is_children,
923 921 entry, pos);
924 922 list_del(&parent->is_children, entry);
925 923 free_iodev(entry);
926 924 } else {
927 925 insert_before(&ss->s_iodevs, entry,
928 926 pos);
929 927 list_del(&ss->s_iodevs, entry);
930 928 free_iodev(entry);
931 929 }
932 930 entry = pos;
933 931 }
934 932 }
935 933 }
936 934 return (0);
937 935 }
938 936
939 937 /*
940 938 * We have the LTI kstat, now add an entry for the LT that sums up all of
941 939 * the LTI's with the same target(t).
942 940 */
943 941 static int
944 942 create_lt(struct snapshot *ss, struct iodev_snapshot *list)
945 943 {
946 944 struct iodev_snapshot *entry, *parent, *pos;
947 945 int lun, tgt, initiator;
948 946 char lun_name[KSTAT_STRLEN];
949 947 char tgt_name[KSTAT_STRLEN];
950 948 char initiator_name[KSTAT_STRLEN];
951 949 int err;
952 950
953 951 for (entry = list; entry; entry = entry->is_next) {
954 952 if ((err = create_lt(ss, entry->is_children)) != 0)
955 953 return (err);
956 954
957 955 if (entry->is_type == IODEV_IOPATH_LTI) {
958 956 parent = find_parent(ss, entry);
959 957 if (get_lti(entry->is_name, lun_name, &lun,
960 958 tgt_name, &tgt, initiator_name, &initiator) != 1) {
961 959 return (1);
962 960 }
963 961
964 962 pos = (parent == NULL) ? NULL : parent->is_children;
965 963 for (; pos; pos = pos->is_next) {
966 964 if (pos->is_id.id != -1 &&
967 965 pos->is_id.id == tgt &&
968 966 pos->is_type == IODEV_IOPATH_LT) {
969 967 /* found the same target */
970 968 update_target(pos, entry);
971 969 break;
972 970 }
973 971 }
974 972
975 973 if (!pos) {
976 974 pos = make_extended_device(
977 975 IODEV_IOPATH_LT, entry);
978 976 update_target(pos, entry);
979 977
980 978 if (parent) {
981 979 insert_before(&parent->is_children,
982 980 entry, pos);
983 981 parent->is_nr_children++;
984 982 } else {
985 983 insert_before(&ss->s_iodevs,
986 984 entry, pos);
987 985 }
988 986 }
989 987 }
990 988 }
991 989 return (0);
992 990 }
993 991
994 992 /* Find the longest is_name field to aid formatting of output */
995 993 static int
996 994 iodevs_is_name_maxlen(struct iodev_snapshot *list)
997 995 {
998 996 struct iodev_snapshot *entry;
999 997 int max = 0, cmax, len;
1000 998
1001 999 for (entry = list; entry; entry = entry->is_next) {
1002 1000 cmax = iodevs_is_name_maxlen(entry->is_children);
1003 1001 max = (cmax > max) ? cmax : max;
1004 1002 len = strlen(entry->is_name);
1005 1003 max = (len > max) ? len : max;
1006 1004 }
1007 1005 return (max);
1008 1006 }
1009 1007
1010 1008 int
1011 1009 acquire_iodevs(struct snapshot *ss, kstat_ctl_t *kc, struct iodev_filter *df)
1012 1010 {
1013 1011 kstat_t *ksp;
1014 1012 struct iodev_snapshot *pos;
1015 1013 struct iodev_snapshot *list = NULL;
1016 1014 int err = 0;
1017 1015
1018 1016 ss->s_nr_iodevs = 0;
1019 1017 ss->s_iodevs_is_name_maxlen = 0;
1020 1018
1021 1019 /*
1022 1020 * Call cleanup_iodevs_snapshot() so that a cache miss in
1023 1021 * lookup_ks_name() will result in a fresh snapshot.
1024 1022 */
1025 1023 cleanup_iodevs_snapshot();
1026 1024
1027 1025 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
1028 1026 enum iodev_type type;
1029 1027
1030 1028 if (ksp->ks_type != KSTAT_TYPE_IO)
1031 1029 continue;
1032 1030
1033 1031 /* e.g. "usb_byte_count" is not handled */
1034 1032 if ((type = get_iodev_type(ksp)) == IODEV_UNKNOWN)
1035 1033 continue;
1036 1034
1037 1035 if (df && !(type & df->if_allowed_types))
1038 1036 continue;
1039 1037
1040 1038 if ((pos = malloc(sizeof (struct iodev_snapshot))) == NULL) {
1041 1039 err = errno;
1042 1040 goto out;
1043 1041 }
1044 1042
1045 1043 (void) memset(pos, 0, sizeof (struct iodev_snapshot));
1046 1044
1047 1045 pos->is_type = type;
1048 1046 pos->is_crtime = ksp->ks_crtime;
1049 1047 pos->is_snaptime = ksp->ks_snaptime;
1050 1048 pos->is_id.id = IODEV_NO_ID;
1051 1049 pos->is_parent_id.id = IODEV_NO_ID;
1052 1050 pos->is_ksp = ksp;
1053 1051 pos->is_instance = ksp->ks_instance;
1054 1052
1055 1053 (void) strlcpy(pos->is_module, ksp->ks_module, KSTAT_STRLEN);
1056 1054 (void) strlcpy(pos->is_name, ksp->ks_name, KSTAT_STRLEN);
1057 1055 get_pretty_name(ss->s_types, pos, kc);
1058 1056
1059 1057 /*
1060 1058 * We must insert in sort order so e.g. vmstat -l
1061 1059 * chooses in order.
1062 1060 */
1063 1061 insert_into(&list, pos);
1064 1062 }
1065 1063
1066 1064 choose_iodevs(ss, list, df);
1067 1065
1068 1066 /* before acquire_stats for collate_controller()'s benefit */
1069 1067 if (ss->s_types & SNAP_IODEV_ERRORS) {
1070 1068 if ((err = acquire_iodev_errors(ss, kc)) != 0)
1071 1069 goto out;
1072 1070 }
1073 1071
1074 1072 if ((err = acquire_iodev_stats(ss->s_iodevs, kc)) != 0)
1075 1073 goto out;
1076 1074
1077 1075 if (ss->s_types & SNAP_IOPATHS_LTI) {
1078 1076 /*
1079 1077 * -Y: kstats are LTI, need to create a synthetic LT
1080 1078 * for -Y output.
1081 1079 */
1082 1080 if ((err = create_lt(ss, ss->s_iodevs)) != 0) {
1083 1081 return (err);
1084 1082 }
1085 1083 }
1086 1084 if (ss->s_types & SNAP_IOPATHS_LI) {
1087 1085 /*
1088 1086 * -X: kstats are LTI, need to create a synthetic LI and
1089 1087 * delete the LTI for -X output
1090 1088 */
1091 1089 if ((err = create_li_delete_lti(ss, ss->s_iodevs)) != 0) {
1092 1090 return (err);
1093 1091 }
1094 1092 }
1095 1093
1096 1094 /* determine width of longest is_name */
1097 1095 ss->s_iodevs_is_name_maxlen = iodevs_is_name_maxlen(ss->s_iodevs);
1098 1096
1099 1097 err = 0;
1100 1098 out:
1101 1099 return (err);
1102 1100 }
1103 1101
1104 1102 void
1105 1103 free_iodev(struct iodev_snapshot *iodev)
1106 1104 {
1107 1105 while (iodev->is_children) {
1108 1106 struct iodev_snapshot *tmp = iodev->is_children;
1109 1107 iodev->is_children = iodev->is_children->is_next;
1110 1108 free_iodev(tmp);
1111 1109 }
1112 1110
1113 1111 if (iodev->avl_list) {
1114 1112 avl_remove(iodev->avl_list, iodev);
1115 1113 if (avl_numnodes(iodev->avl_list) == 0) {
1116 1114 avl_destroy(iodev->avl_list);
1117 1115 free(iodev->avl_list);
1118 1116 }
1119 1117 }
1120 1118
1121 1119 free(iodev->is_errors.ks_data);
1122 1120 free(iodev->is_pretty);
1123 1121 free(iodev->is_dname);
1124 1122 free(iodev->is_devid);
1125 1123 free(iodev);
1126 1124 }
↓ open down ↓ |
964 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX