|
|
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.