|
|
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 "mkdev.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: #ifdef USE_PROTO ! 48: LOCAL int (chr_sel) (mdev_t * mdevp) ! 49: #else ! 50: LOCAL int ! 51: chr_sel ARGS ((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: #ifdef USE_PROTO ! 66: LOCAL int (chr_pred) (mdev_t * left, mdev_t * right) ! 67: #else ! 68: LOCAL int ! 69: chr_pred ARGS ((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: #ifdef USE_PROTO ! 83: LOCAL int (blk_sel) (mdev_t * mdevp) ! 84: #else ! 85: LOCAL int ! 86: blk_sel ARGS ((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: #ifdef USE_PROTO ! 101: LOCAL int (blk_pred) (mdev_t * left, mdev_t * right) ! 102: #else ! 103: LOCAL int ! 104: blk_pred ARGS ((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: #ifdef USE_PROTO ! 118: LOCAL int (mod_sel) (mdev_t * mdevp) ! 119: #else ! 120: LOCAL int ! 121: mod_sel ARGS ((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: * This is where we build the external->internal major number mapping table. ! 133: * ! 134: * The external->internal device number system becomes immediately useful ! 135: * under STREAMS, where a) STREAMS cannot use device major numbers lower than ! 136: * MAJOR_RESERVED under Coherent, and b) Coherent uses old-style 16-bit ! 137: * dev_t's, so that the ability to transform a range of external majors into ! 138: * a contiguous sequence of internal minor numbers will be of immediate value ! 139: * in supporting connection-oriented services (although this is also pending ! 140: * on the addition of support for cloning to the kernel). ! 141: * ! 142: * Mapping between internal and external numbers is not simple; what makes it ! 143: * worse is that because there is a single mapping that has to be the same ! 144: * for both block and character tables, the construction of the bdevsw [] and ! 145: * cdevsw [] internal tables is constrained. This is only a problem if ! 146: * multiple external major numbers are allowed, and each device is only ! 147: * permitted to have a single internal major number. The interpretation of the ! 148: * 'M' flag in this circumstance is unclear. ! 149: * ! 150: * The assign_imajors () code should be able to deal with the most complex ! 151: * case, which is where multiple external majors may actually be mapped to ! 152: * multiple internal numbers, thus ! 153: * ! 154: * Block external : |-----scsi-------| ! 155: * Character external: |--tcp--| |-udp-| |ttys| ! 156: * ! 157: * Might map 'tcp' to internal 0, 'udp' to internal 1, 'ttys' to internal 2, ! 158: * while 'scsi' would have 0, 1, and 2 as internal major numbers. ! 159: * ! 160: * This is all hypothetical at the moment, since multiple majors are new to ! 161: * Coherent anyway. For simplicity, we may constrain the above to be an error ! 162: * by requiring unique internal number for each device. However, the machinery ! 163: * in assign_imajors () will have to be flexible enough to deal with the ! 164: * above. ! 165: * ! 166: * NOTE: The complex model is only applicable if a device does not care what ! 167: * minor numbers are given to it, since there is a single shared table used ! 168: * to map a range of external major numbers into a range of internal minor ! 169: * numbers. Since this table is shared, it constrains even more heavily the ! 170: * circumstances in which numbers can overlap. Without a flag to detect when ! 171: * a driver doesn't care about minor numbers, we simply forget about the ! 172: * complex model. ! 173: */ ! 174: ! 175: /* ! 176: * Definitions used to control parts of the way assign_imajors () deals with ! 177: * the external->internal mapping (as discussed above). The main things we ! 178: * isolate here are the calculations of the upper bounds for table allocations ! 179: * since the constraint of a common mapping means that the cdevsw [] and ! 180: * bdevsw [] tables may be larger than a separate mapping would permit. ! 181: * ! 182: * In particular, if ncdevs is the number of character devices and nbdevs is ! 183: * the number of block devices, the upper bound on table size is: ! 184: * Simple model: block = char = max (ncdevs, nbdevs) ! 185: * Complex model: char = ncdevs + max (nbdevs - 1, 0) ! 186: * block = nbdevs + max (ncdevs - 1, 0) ! 187: */ ! 188: ! 189: #define MAX(a,b) ((a) > (b) ? (a) : (b)) ! 190: #define MIN(a,b) ((a) < (b) ? (a) : (b)) ! 191: ! 192: #define MAX_CHR_IMAJORS(c,b) MAX (c, b) ! 193: #define MAX_BLK_IMAJORS(c,b) MAX (c, b) ! 194: ! 195: ! 196: /* ! 197: * Assign internal major numbers to devices. For now, this function does not ! 198: * attempt to deal with assigning major number ranges. ! 199: */ ! 200: ! 201: #ifdef USE_PROTO ! 202: extinfo_t * (assign_imajors) (void) ! 203: #else ! 204: extinfo_t * ! 205: assign_imajors ARGS (()) ! 206: #endif ! 207: { ! 208: extinfo_t * extinfop; ! 209: mdlist_t blklist; ! 210: mdlist_t chrlist; ! 211: mdlist_t modlist; ! 212: ! 213: int nemajors; ! 214: int i; ! 215: ! 216: ! 217: /* ! 218: * The algorithm for assigning internal numbers for the block and ! 219: * character-device tables will be able to run in a single pass if we ! 220: * are able to provide lists of character and block devices sorted by ! 221: * beginning external major number. This sort process also provides us ! 222: * a variety of other useful information directly, such as the maximum ! 223: * external number used. ! 224: */ ! 225: ! 226: mdev_sort (& chrlist, chr_sel, chr_pred, offsetof (mdev_t, md_link1)); ! 227: mdev_sort (& blklist, blk_sel, blk_pred, offsetof (mdev_t, md_link2)); ! 228: mdev_sort (& modlist, mod_sel, NULL, offsetof (mdev_t, md_link3)); ! 229: ! 230: nemajors = 0; ! 231: ! 232: if (chrlist.mdl_last != NULL) ! 233: nemajors = MAX (nemajors, chrlist.mdl_last->md_chr_maj [1]); ! 234: ! 235: if (blklist.mdl_last != NULL) ! 236: nemajors = MAX (nemajors, blklist.mdl_last->md_blk_maj [1]); ! 237: ! 238: nemajors ++; ! 239: ! 240: ! 241: /* ! 242: * Now we know how many of everything there is, allocate space for ! 243: * tables. ! 244: */ ! 245: ! 246: i = sizeof (* extinfop) + ! 247: sizeof (mdev_t *) * (MAX_CHR_IMAJORS (chrlist.mdl_count, ! 248: blklist.mdl_count) + ! 249: MAX_BLK_IMAJORS (chrlist.mdl_count, ! 250: blklist.mdl_count) + ! 251: modlist.mdl_count) + ! 252: 2 * sizeof (minor_t) * nemajors; ! 253: ! 254: if ((extinfop = (extinfo_t *) malloc (i)) == NULL) ! 255: throw_error ("insufficient memory in assign_imajors ()"); ! 256: ! 257: extinfop->ei_etoimajor = (minor_t *) (extinfop + 1); ! 258: extinfop->ei_minoroffset = extinfop->ei_etoimajor + nemajors; ! 259: extinfop->ei_modules = (mdev_t **) (extinfop->ei_minoroffset + ! 260: nemajors); ! 261: extinfop->ei_cdevsw = extinfop->ei_modules + modlist.mdl_count; ! 262: extinfop->ei_bdevsw = extinfop->ei_cdevsw + ! 263: MAX_CHR_IMAJORS (chrlist.mdl_count, ! 264: blklist.mdl_count); ! 265: ! 266: /* ! 267: * Since we allocate space for the maximum number of table entries, ! 268: * the loops below assign internal numbers which may not be ! 269: * contiguous, or may be below the upper limit allocated. ! 270: */ ! 271: ! 272: extinfop->ei_nemajors = nemajors; ! 273: extinfop->ei_ncdevs = 0; ! 274: extinfop->ei_nbdevs = 0; ! 275: extinfop->ei_nmodules = modlist.mdl_count; ! 276: ! 277: for (i = 0 ; i < nemajors ; i ++) { ! 278: ! 279: extinfop->ei_etoimajor [i] = NODEV; ! 280: extinfop->ei_minoroffset [i] = 0; ! 281: } ! 282: ! 283: ! 284: for (i = 0 ; i < MAX_CHR_IMAJORS (chrlist.mdl_count, ! 285: blklist.mdl_count) ; i ++) { ! 286: extinfop->ei_cdevsw [i] = NULL; ! 287: } ! 288: ! 289: for (i = 0 ; i < MAX_BLK_IMAJORS (chrlist.mdl_count, ! 290: blklist.mdl_count) ; i ++) { ! 291: extinfop->ei_bdevsw [i] = NULL; ! 292: } ! 293: ! 294: ! 295: ! 296: while (chrlist.mdl_first != NULL || blklist.mdl_first != NULL) { ! 297: mdev_t * chrp; ! 298: mdev_t * blkp; ! 299: int extlo; ! 300: int exthi; ! 301: int internal; ! 302: int minorinc; ! 303: int minorofs; ! 304: ! 305: /* ! 306: * Choose a range of external numbers that we are going to ! 307: * assign to a single internal number. If our choice is not ! 308: * constrained by an overlap between character and block ! 309: * external numbers, then we deal with that. ! 310: */ ! 311: ! 312: blkp = blklist.mdl_first; ! 313: ! 314: if ((chrp = chrlist.mdl_first) != NULL) { ! 315: ! 316: extlo = chrp->md_chr_maj [0]; ! 317: exthi = chrp->md_chr_maj [1]; ! 318: minorinc = chrp->md_minor_max; ! 319: ! 320: if (blkp != NULL) { ! 321: ! 322: if (blkp->md_blk_maj [1] < extlo) { ! 323: ! 324: chrp = NULL; ! 325: goto doblock; ! 326: } ! 327: ! 328: if (blkp->md_blk_maj [0] > exthi) { ! 329: blkp = NULL; ! 330: goto dochar; ! 331: } ! 332: ! 333: /* ! 334: * Because of minor-number mapping, overlap is ! 335: * only valid in special circumstances. ! 336: */ ! 337: ! 338: if (blkp->md_blk_maj [0] != extlo || ! 339: (blkp->md_minor_max != minorinc && ! 340: blkp->md_blk_maj [1] > ! 341: blkp->md_blk_maj [0] && ! 342: exthi > extlo)) { ! 343: ! 344: free (extinfop); ! 345: throw_error ("minor number mapping conflict"); ! 346: } ! 347: ! 348: ! 349: /* ! 350: * Choose a suitable internal major number. ! 351: */ ! 352: ! 353: if (exthi < blkp->md_blk_maj [1]) { ! 354: ! 355: exthi = blkp->md_blk_maj [1]; ! 356: minorinc = blkp->md_minor_max; ! 357: } ! 358: ! 359: internal = MAX (extinfop->ei_ncdevs, ! 360: extinfop->ei_nbdevs); ! 361: ! 362: goto done; ! 363: } ! 364: dochar: ! 365: /* ! 366: * Simple case, select an internal number. ! 367: */ ! 368: ! 369: for (internal = 0 ; ! 370: extinfop->ei_cdevsw [internal] != NULL ; ! 371: internal ++) ! 372: ; ! 373: ! 374: if (internal > extinfop->ei_ncdevs) { ! 375: ! 376: free (extinfop); ! 377: throw_error ("internal check failed, assign_imajors ()"); ! 378: } ! 379: } else { ! 380: /* ! 381: * Simple case for block device, select an internal ! 382: * number. ! 383: */ ! 384: ! 385: doblock: ! 386: extlo = blkp->md_blk_maj [0]; ! 387: exthi = blkp->md_blk_maj [1]; ! 388: minorinc = blkp->md_minor_max; ! 389: ! 390: for (internal = 0 ; ! 391: extinfop->ei_bdevsw [internal] != NULL ; ! 392: internal ++) ! 393: ; ! 394: ! 395: if (internal > extinfop->ei_nbdevs) { ! 396: ! 397: free (extinfop); ! 398: throw_error ("internal check failed, assign_imajors ()"); ! 399: } ! 400: } ! 401: done: ! 402: /* ! 403: * Now we have decided when, where, and how much, fill in the ! 404: * table. ! 405: */ ! 406: ! 407: minorofs = 0; ! 408: ! 409: while (extlo <= exthi) { ! 410: ! 411: if (extinfop->ei_etoimajor [extlo] != NODEV) { ! 412: ! 413: free (extinfop); ! 414: throw_error ("major-number mapping conflict"); ! 415: } ! 416: ! 417: extinfop->ei_etoimajor [extlo] = internal; ! 418: extinfop->ei_minoroffset [extlo] = minorofs; ! 419: ! 420: minorofs += minorinc; ! 421: extlo ++; ! 422: } ! 423: ! 424: if ((extinfop->ei_cdevsw [internal] = chrp) != NULL) { ! 425: ! 426: if (internal >= extinfop->ei_ncdevs) ! 427: extinfop->ei_ncdevs = internal + 1; ! 428: ! 429: chrlist.mdl_first = chrp->md_link1; ! 430: } ! 431: ! 432: ! 433: if ((extinfop->ei_bdevsw [internal] = blkp) != NULL) { ! 434: ! 435: if (internal >= extinfop->ei_nbdevs) ! 436: extinfop->ei_nbdevs = internal + 1; ! 437: ! 438: blklist.mdl_first = blkp->md_link2; ! 439: } ! 440: } ! 441: ! 442: ! 443: /* ! 444: * Now we can build a table of all the STREAMS modules. ! 445: */ ! 446: ! 447: i = 0; ! 448: ! 449: while (modlist.mdl_first != NULL) { ! 450: ! 451: extinfop->ei_modules [i ++] = modlist.mdl_first; ! 452: ! 453: modlist.mdl_first = modlist.mdl_first->md_link3; ! 454: } ! 455: ! 456: if (i != modlist.mdl_count) { ! 457: ! 458: free (extinfop); ! 459: throw_error ("internal consistency check failed in assign_imajors ()"); ! 460: } ! 461: ! 462: return extinfop; ! 463: } ! 464:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.