|
|
1.1 ! root 1: #define _DDI_DKI 1 ! 2: #define _SYSV4 1 ! 3: ! 4: /* ! 5: * This file assigns device major and minor numbers based on configuration ! 6: * data read in by "devadm.c". ! 7: */ ! 8: /* ! 9: *-IMPORTS: ! 10: * <sys/compat.h> ! 11: * CONST ! 12: * PROTO ! 13: * ARGS () ! 14: * LOCAL ! 15: * <kernel/v_types.h> ! 16: * NODEV ! 17: * major_t ! 18: * minor_t ! 19: * <stddef.h> ! 20: * size_t ! 21: * offsetof () ! 22: * <stdlib.h> ! 23: * NULL ! 24: * free () ! 25: * malloc () ! 26: * "ehand.h" ! 27: * throw_error () ! 28: * "mdev.h" ! 29: * mdev_t ! 30: * mdev_sort () ! 31: */ ! 32: ! 33: #include <sys/compat.h> ! 34: #include <kernel/v_types.h> ! 35: #include <stddef.h> ! 36: #include <stdlib.h> ! 37: ! 38: #include "ehand.h" ! 39: #include "mdev.h" ! 40: ! 41: #include "assign.h" ! 42: ! 43: /* ! 44: * Selection predicate for choosing enabled character devices. ! 45: */ ! 46: ! 47: #if USE_PROTO ! 48: LOCAL int chr_sel (mdev_t * mdevp) ! 49: #else ! 50: LOCAL int ! 51: chr_sel (mdevp) ! 52: mdev_t * mdevp; ! 53: #endif ! 54: { ! 55: return mdevp->md_configure == MD_ENABLED && ! 56: mdev_flag (mdevp, MDEV_CHAR); ! 57: } ! 58: ! 59: ! 60: /* ! 61: * Predicate for comparing two mdevice entries on the basis of minimum ! 62: * external character-device number. ! 63: */ ! 64: ! 65: #if USE_PROTO ! 66: LOCAL int chr_pred (mdev_t * left, mdev_t * right) ! 67: #else ! 68: LOCAL int ! 69: chr_pred (left, right) ! 70: mdev_t * left; ! 71: mdev_t * right; ! 72: #endif ! 73: { ! 74: return left->md_chr_maj [0] < right->md_chr_maj [0]; ! 75: } ! 76: ! 77: ! 78: /* ! 79: * Selection predicate for choosing enabled block devices. ! 80: */ ! 81: ! 82: #if USE_PROTO ! 83: LOCAL int blk_sel (mdev_t * mdevp) ! 84: #else ! 85: LOCAL int ! 86: blk_sel (mdevp) ! 87: mdev_t * mdevp; ! 88: #endif ! 89: { ! 90: return mdevp->md_configure == MD_ENABLED && ! 91: mdev_flag (mdevp, MDEV_BLOCK); ! 92: } ! 93: ! 94: ! 95: /* ! 96: * Predicate for comparing two mdevice entries on the basis of minimum ! 97: * external block-device number. ! 98: */ ! 99: ! 100: #if USE_PROTO ! 101: LOCAL int blk_pred (mdev_t * left, mdev_t * right) ! 102: #else ! 103: LOCAL int ! 104: blk_pred (left, right) ! 105: mdev_t * left; ! 106: mdev_t * right; ! 107: #endif ! 108: { ! 109: return left->md_blk_maj [0] < right->md_blk_maj [0]; ! 110: } ! 111: ! 112: ! 113: /* ! 114: * Predicate for selecting modules (streams drivers that are not devices). ! 115: */ ! 116: ! 117: #if USE_PROTO ! 118: LOCAL int mod_sel (mdev_t * mdevp) ! 119: #else ! 120: LOCAL int ! 121: mod_sel (mdevp) ! 122: mdev_t * mdevp; ! 123: #endif ! 124: { ! 125: return mdevp->md_configure == MD_ENABLED && ! 126: mdev_flag (mdevp, MDEV_STREAM) && ! 127: ! mdev_flag (mdevp, MDEV_CHAR); ! 128: } ! 129: ! 130: ! 131: /* ! 132: * Predicate for selecting Coherent drivers. ! 133: */ ! 134: ! 135: #if USE_PROTO ! 136: LOCAL int coh_sel (mdev_t * mdevp) ! 137: #else ! 138: LOCAL int ! 139: coh_sel (mdevp) ! 140: mdev_t * mdevp; ! 141: #endif ! 142: { ! 143: return mdevp->md_configure == MD_ENABLED && ! 144: mdev_flag (mdevp, MDEV_COHERENT); ! 145: } ! 146: ! 147: ! 148: /* ! 149: * Predicate for comparing two Coherent devices on the basis of major number. ! 150: */ ! 151: ! 152: #if USE_PROTO ! 153: LOCAL int coh_pred (mdev_t * left, mdev_t * right) ! 154: #else ! 155: LOCAL int ! 156: coh_pred (left, right) ! 157: mdev_t * left; ! 158: mdev_t * right; ! 159: #endif ! 160: { ! 161: return left->md_blk_maj [0] < right->md_blk_maj [0]; ! 162: } ! 163: ! 164: ! 165: /* ! 166: * This is where we build the external->internal major number mapping table. ! 167: * ! 168: * The external->internal device number system becomes immediately useful ! 169: * under STREAMS, where a) STREAMS cannot use device major numbers lower than ! 170: * MAJOR_RESERVED under Coherent, and b) Coherent uses old-style 16-bit ! 171: * dev_t's, so that the ability to transform a range of external majors into ! 172: * a contiguous sequence of internal minor numbers will be of immediate value ! 173: * in supporting connection-oriented services (although this is also pending ! 174: * on the addition of support for cloning to the kernel). ! 175: * ! 176: * Mapping between internal and external numbers is not simple; what makes it ! 177: * worse is that because there is a single mapping that has to be the same ! 178: * for both block and character tables, the construction of the bdevsw [] and ! 179: * cdevsw [] internal tables is constrained. This is only a problem if ! 180: * multiple external major numbers are allowed, and each device is only ! 181: * permitted to have a single internal major number. The interpretation of the ! 182: * 'M' flag in this circumstance is unclear. ! 183: * ! 184: * The assign_imajors () code should be able to deal with the most complex ! 185: * case, which is where multiple external majors may actually be mapped to ! 186: * multiple internal numbers, thus ! 187: * ! 188: * Block external : |-----scsi-------| ! 189: * Character external: |--tcp--| |-udp-| |ttys| ! 190: * ! 191: * Might map 'tcp' to internal 0, 'udp' to internal 1, 'ttys' to internal 2, ! 192: * while 'scsi' would have 0, 1, and 2 as internal major numbers. ! 193: * ! 194: * This is all hypothetical at the moment, since multiple majors are new to ! 195: * Coherent anyway. For simplicity, we may constrain the above to be an error ! 196: * by requiring unique internal number for each device. However, the machinery ! 197: * in assign_imajors () will have to be flexible enough to deal with the ! 198: * above. ! 199: * ! 200: * NOTE: The complex model is only applicable if a device does not care what ! 201: * minor numbers are given to it, since there is a single shared table used ! 202: * to map a range of external major numbers into a range of internal minor ! 203: * numbers. Since this table is shared, it constrains even more heavily the ! 204: * circumstances in which numbers can overlap. Without a flag to detect when ! 205: * a driver doesn't care about minor numbers, we simply forget about the ! 206: * complex model. ! 207: */ ! 208: ! 209: /* ! 210: * Definitions used to control parts of the way assign_imajors () deals with ! 211: * the external->internal mapping (as discussed above). The main things we ! 212: * isolate here are the calculations of the upper bounds for table allocations ! 213: * since the constraint of a common mapping means that the cdevsw [] and ! 214: * bdevsw [] tables may be larger than a separate mapping would permit. ! 215: * ! 216: * In particular, if ncdevs is the number of character devices and nbdevs is ! 217: * the number of block devices, the upper bound on table size is: ! 218: * Simple model: block = char = max (ncdevs, nbdevs) ! 219: * Complex model: char = ncdevs + max (nbdevs - 1, 0) ! 220: * block = nbdevs + max (ncdevs - 1, 0) ! 221: */ ! 222: ! 223: #define MAX(a,b) ((a) > (b) ? (a) : (b)) ! 224: #define MIN(a,b) ((a) < (b) ? (a) : (b)) ! 225: ! 226: #define MAX_CHR_IMAJORS(c,b) MAX (c, b) ! 227: #define MAX_BLK_IMAJORS(c,b) MAX (c, b) ! 228: ! 229: ! 230: /* ! 231: * Assign internal major numbers to devices. For now, this function does not ! 232: * attempt to deal with assigning major number ranges. ! 233: */ ! 234: ! 235: #if USE_PROTO ! 236: extinfo_t * (assign_imajors) (void) ! 237: #else ! 238: extinfo_t * ! 239: assign_imajors ARGS (()) ! 240: #endif ! 241: { ! 242: extinfo_t * extinfop; ! 243: mdev_t * blk_list; ! 244: mdev_t * blk_end; ! 245: mdev_t * chr_list; ! 246: mdev_t * chr_end; ! 247: mdev_t * mod_list; ! 248: mdev_t * coh_list; ! 249: int n_blk_list; ! 250: int n_chr_list; ! 251: int n_mod_list; ! 252: int n_coh_list; ! 253: ! 254: int nemajors; ! 255: int i; ! 256: ! 257: ! 258: /* ! 259: * The algorithm for assigning internal numbers for the block and ! 260: * character-device tables will be able to run in a single pass if we ! 261: * are able to provide lists of character and block devices sorted by ! 262: * beginning external major number. This sort process also provides us ! 263: * a variety of other useful information directly, such as the maximum ! 264: * external number used. ! 265: */ ! 266: ! 267: n_chr_list = mdev_sort (& chr_list, & chr_end, chr_sel, chr_pred, ! 268: offsetof (mdev_t, md_chrlink)); ! 269: n_blk_list = mdev_sort (& blk_list, & blk_end, blk_sel, blk_pred, ! 270: offsetof (mdev_t, md_blklink)); ! 271: n_mod_list = mdev_sort (& mod_list, NULL, mod_sel, NULL, ! 272: offsetof (mdev_t, md_modlink)); ! 273: n_coh_list = mdev_sort (& coh_list, NULL, coh_sel, coh_pred, ! 274: offsetof (mdev_t, md_cohlink)); ! 275: ! 276: nemajors = 0; ! 277: ! 278: if (chr_end != NULL) ! 279: nemajors = MAX (nemajors, chr_end->md_chr_maj [1]); ! 280: ! 281: if (blk_end != NULL) ! 282: nemajors = MAX (nemajors, blk_end->md_blk_maj [1]); ! 283: ! 284: nemajors ++; ! 285: ! 286: ! 287: /* ! 288: * Now we know how many of everything there is, allocate space for ! 289: * tables. ! 290: */ ! 291: ! 292: i = sizeof (* extinfop) + ! 293: sizeof (mdev_t *) * (MAX_CHR_IMAJORS (n_chr_list, n_blk_list) + ! 294: MAX_BLK_IMAJORS (n_chr_list, n_blk_list) + ! 295: n_mod_list + n_coh_list) + ! 296: 2 * sizeof (minor_t) * nemajors; ! 297: ! 298: if ((extinfop = (extinfo_t *) malloc (i)) == NULL) ! 299: throw_error ("insufficient memory in assign_imajors ()"); ! 300: ! 301: extinfop->ei_etoimajor = (minor_t *) (extinfop + 1); ! 302: extinfop->ei_minoroffset = extinfop->ei_etoimajor + nemajors; ! 303: extinfop->ei_modules = (mdev_t **) (extinfop->ei_minoroffset + ! 304: nemajors); ! 305: extinfop->ei_cohdrivers = extinfop->ei_modules + n_mod_list; ! 306: extinfop->ei_cdevsw = extinfop->ei_cohdrivers + n_coh_list; ! 307: extinfop->ei_bdevsw = extinfop->ei_cdevsw + ! 308: MAX_CHR_IMAJORS (n_chr_list, n_blk_list); ! 309: ! 310: /* ! 311: * Since we allocate space for the maximum number of table entries, ! 312: * the loops below assign internal numbers which may not be ! 313: * contiguous, or may be below the upper limit allocated. ! 314: */ ! 315: ! 316: extinfop->ei_nemajors = nemajors; ! 317: extinfop->ei_ncdevs = 0; ! 318: extinfop->ei_nbdevs = 0; ! 319: extinfop->ei_nmodules = n_mod_list; ! 320: extinfop->ei_ncohdrivers = n_coh_list; ! 321: ! 322: for (i = 0 ; i < nemajors ; i ++) { ! 323: ! 324: extinfop->ei_etoimajor [i] = NODEV; ! 325: extinfop->ei_minoroffset [i] = 0; ! 326: } ! 327: ! 328: ! 329: for (i = 0 ; i < MAX_CHR_IMAJORS (n_chr_list, n_blk_list) ; i ++) ! 330: extinfop->ei_cdevsw [i] = NULL; ! 331: ! 332: for (i = 0 ; i < MAX_BLK_IMAJORS (n_chr_list, n_blk_list) ; i ++) ! 333: extinfop->ei_bdevsw [i] = NULL; ! 334: ! 335: ! 336: while (chr_list != NULL || blk_list != NULL) { ! 337: mdev_t * chrp; ! 338: mdev_t * blkp; ! 339: int extlo; ! 340: int exthi; ! 341: int internal; ! 342: int minorinc; ! 343: int minorofs; ! 344: ! 345: /* ! 346: * Choose a range of external numbers that we are going to ! 347: * assign to a single internal number. If our choice is not ! 348: * constrained by an overlap between character and block ! 349: * external numbers, then we deal with that. ! 350: */ ! 351: ! 352: blkp = blk_list; ! 353: ! 354: if ((chrp = chr_list) != NULL) { ! 355: ! 356: extlo = chrp->md_chr_maj [0]; ! 357: exthi = chrp->md_chr_maj [1]; ! 358: minorinc = chrp->md_minor_max; ! 359: ! 360: if (blkp != NULL) { ! 361: ! 362: if (blkp->md_blk_maj [1] < extlo) { ! 363: ! 364: chrp = NULL; ! 365: goto doblock; ! 366: } ! 367: ! 368: if (blkp->md_blk_maj [0] > exthi) { ! 369: blkp = NULL; ! 370: goto dochar; ! 371: } ! 372: ! 373: /* ! 374: * Because of minor-number mapping, overlap is ! 375: * only valid in special circumstances. ! 376: */ ! 377: ! 378: if (blkp->md_blk_maj [0] != extlo || ! 379: (blkp->md_minor_max != minorinc && ! 380: blkp->md_blk_maj [1] > ! 381: blkp->md_blk_maj [0] && ! 382: exthi > extlo)) { ! 383: ! 384: free (extinfop); ! 385: throw_error ("minor number mapping conflict"); ! 386: } ! 387: ! 388: ! 389: /* ! 390: * Choose a suitable internal major number. ! 391: */ ! 392: ! 393: if (exthi < blkp->md_blk_maj [1]) { ! 394: ! 395: exthi = blkp->md_blk_maj [1]; ! 396: minorinc = blkp->md_minor_max; ! 397: } ! 398: ! 399: internal = MAX (extinfop->ei_ncdevs, ! 400: extinfop->ei_nbdevs); ! 401: ! 402: goto done; ! 403: } ! 404: dochar: ! 405: /* ! 406: * Simple case, select an internal number. ! 407: */ ! 408: ! 409: for (internal = 0 ; ! 410: extinfop->ei_cdevsw [internal] != NULL ; ! 411: internal ++) ! 412: ; ! 413: ! 414: if (internal > extinfop->ei_ncdevs) { ! 415: ! 416: free (extinfop); ! 417: throw_error ("internal check failed, assign_imajors ()"); ! 418: } ! 419: } else { ! 420: /* ! 421: * Simple case for block device, select an internal ! 422: * number. ! 423: */ ! 424: ! 425: doblock: ! 426: extlo = blkp->md_blk_maj [0]; ! 427: exthi = blkp->md_blk_maj [1]; ! 428: minorinc = blkp->md_minor_max; ! 429: ! 430: for (internal = 0 ; ! 431: extinfop->ei_bdevsw [internal] != NULL ; ! 432: internal ++) ! 433: ; ! 434: ! 435: if (internal > extinfop->ei_nbdevs) { ! 436: ! 437: free (extinfop); ! 438: throw_error ("internal check failed, assign_imajors ()"); ! 439: } ! 440: } ! 441: done: ! 442: /* ! 443: * Now we have decided when, where, and how much, fill in the ! 444: * table. ! 445: */ ! 446: ! 447: minorofs = 0; ! 448: ! 449: while (extlo <= exthi) { ! 450: ! 451: if (extinfop->ei_etoimajor [extlo] != NODEV) { ! 452: ! 453: free (extinfop); ! 454: throw_error ("major-number mapping conflict"); ! 455: } ! 456: ! 457: extinfop->ei_etoimajor [extlo] = internal; ! 458: extinfop->ei_minoroffset [extlo] = minorofs; ! 459: ! 460: minorofs += minorinc; ! 461: extlo ++; ! 462: } ! 463: ! 464: if ((extinfop->ei_cdevsw [internal] = chrp) != NULL) { ! 465: ! 466: if (internal >= extinfop->ei_ncdevs) ! 467: extinfop->ei_ncdevs = internal + 1; ! 468: ! 469: chr_list = chrp->md_chrlink; ! 470: } ! 471: ! 472: ! 473: if ((extinfop->ei_bdevsw [internal] = blkp) != NULL) { ! 474: ! 475: if (internal >= extinfop->ei_nbdevs) ! 476: extinfop->ei_nbdevs = internal + 1; ! 477: ! 478: blk_list = blkp->md_blklink; ! 479: } ! 480: } ! 481: ! 482: ! 483: /* ! 484: * Now we can build a table of all the STREAMS modules. ! 485: */ ! 486: ! 487: i = 0; ! 488: ! 489: while (mod_list != NULL) { ! 490: ! 491: extinfop->ei_modules [i ++] = mod_list; ! 492: mod_list = mod_list->md_modlink; ! 493: } ! 494: ! 495: ! 496: /* ! 497: * Now we can build a table of all the Coherent drivers. ! 498: */ ! 499: ! 500: i = 0; ! 501: ! 502: while (coh_list != NULL) { ! 503: ! 504: extinfop->ei_cohdrivers [i ++] = coh_list; ! 505: coh_list = coh_list->md_cohlink; ! 506: } ! 507: ! 508: return extinfop; ! 509: } ! 510:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.