coverity appeasement
[minix.git] / servers / vfs / dmap.c
blobdeccc8d361464a0821549a0a4207a02191b198d2
1 /* This file contains the table with device <-> driver mappings. It also
2 * contains some routines to dynamically add and/ or remove device drivers
3 * or change mappings.
4 */
6 #include "fs.h"
7 #include <assert.h>
8 #include <string.h>
9 #include <stdlib.h>
10 #include <ctype.h>
11 #include <unistd.h>
12 #include <minix/com.h>
13 #include <minix/ds.h>
14 #include "fproc.h"
15 #include "dmap.h"
16 #include "param.h"
18 /* The order of the entries in the table determines the mapping between major
19 * device numbers and device drivers. Character and block devices
20 * can be intermixed at random. The ordering determines the device numbers in
21 * /dev. Note that the major device numbers used in /dev are NOT the same as
22 * the process numbers of the device drivers. See <minix/dmap.h> for mappings.
25 struct dmap dmap[NR_DEVICES];
27 #define DT_EMPTY { no_dev, no_dev_io, NONE, "", 0, STYLE_NDEV, NULL, NONE, \
28 0, NULL, 0}
30 /*===========================================================================*
31 * lock_dmap *
32 *===========================================================================*/
33 void lock_dmap(struct dmap *dp)
35 /* Lock a driver */
36 struct worker_thread *org_self;
37 struct fproc *org_fp;
38 int r;
40 assert(dp != NULL);
41 assert(dp->dmap_driver != NONE);
43 org_fp = fp;
44 org_self = self;
46 if ((r = mutex_lock(dp->dmap_lock_ref)) != 0)
47 panic("unable to get a lock on dmap: %d\n", r);
49 fp = org_fp;
50 self = org_self;
53 /*===========================================================================*
54 * unlock_dmap *
55 *===========================================================================*/
56 void unlock_dmap(struct dmap *dp)
58 /* Unlock a driver */
59 int r;
61 assert(dp != NULL);
63 if ((r = mutex_unlock(dp->dmap_lock_ref)) != 0)
64 panic("unable to unlock dmap lock: %d\n", r);
67 /*===========================================================================*
68 * do_mapdriver *
69 *===========================================================================*/
70 int do_mapdriver()
72 /* Create a device->driver mapping. RS will tell us which major is driven by
73 * this driver, what type of device it is (regular, TTY, asynchronous, clone,
74 * etc), and its label. This label is registered with DS, and allows us to
75 * retrieve the driver's endpoint.
77 int r, flags, major, style;
78 endpoint_t endpoint;
79 vir_bytes label_vir;
80 size_t label_len;
81 char label[LABEL_MAX];
83 /* Only RS can map drivers. */
84 if (who_e != RS_PROC_NR) return(EPERM);
86 label_vir = (vir_bytes) job_m_in.md_label;
87 label_len = (size_t) job_m_in.md_label_len;
88 major = job_m_in.md_major;
89 flags = job_m_in.md_flags;
90 style = job_m_in.md_style;
92 /* Get the label */
93 if (label_len+1 > sizeof(label)) { /* Can we store this label? */
94 printf("VFS: do_mapdriver: label too long\n");
95 return(EINVAL);
97 r = sys_vircopy(who_e, label_vir, SELF, (vir_bytes) label, label_len);
98 if (r != OK) {
99 printf("VFS: do_mapdriver: sys_vircopy failed: %d\n", r);
100 return(EINVAL);
102 label[label_len] = '\0'; /* Terminate label */
104 /* Now we know how the driver is called, fetch its endpoint */
105 r = ds_retrieve_label_endpt(label, &endpoint);
106 if (r != OK) {
107 printf("VFS: do_mapdriver: label '%s' unknown\n", label);
108 return(EINVAL);
111 /* Try to update device mapping. */
112 return map_driver(label, major, endpoint, style, flags);
115 /*===========================================================================*
116 * map_driver *
117 *===========================================================================*/
118 int map_driver(label, major, proc_nr_e, style, flags)
119 const char label[LABEL_MAX]; /* name of the driver */
120 int major; /* major number of the device */
121 endpoint_t proc_nr_e; /* process number of the driver */
122 int style; /* style of the device */
123 int flags; /* device flags */
125 /* Add a new device driver mapping in the dmap table. If the proc_nr is set to
126 * NONE, we're supposed to unmap it.
129 int slot, s;
130 size_t len;
131 struct dmap *dp;
132 struct fproc *rfp;
134 /* Get pointer to device entry in the dmap table. */
135 if (major < 0 || major >= NR_DEVICES) return(ENODEV);
136 dp = &dmap[major];
138 /* Check if we're supposed to unmap it. */
139 if (proc_nr_e == NONE) {
140 /* Even when a driver is now unmapped and is shortly to be mapped in
141 * due to recovery, invalidate associated filps if they're character
142 * special files. More sophisticated recovery mechanisms which would
143 * reduce the need to invalidate files are possible, but would require
144 * cooperation of the driver and more recovery framework between RS,
145 * VFS, and DS.
147 invalidate_filp_by_char_major(major);
148 dp->dmap_opcl = no_dev;
149 dp->dmap_io = no_dev_io;
150 dp->dmap_driver = NONE;
151 dp->dmap_flags = flags;
152 dp->dmap_lock_ref = &dp->dmap_lock;
153 return(OK);
156 /* Check process number of new driver if it was alive before mapping */
157 s = isokendpt(proc_nr_e, &slot);
158 if (s != OK) {
159 /* This is not a problem only when we force this driver mapping */
160 if (! (flags & DRV_FORCED))
161 return(EINVAL);
162 } else {
163 rfp = &fproc[slot];
164 rfp->fp_flags |= FP_SYS_PROC; /* Process is a driver */
167 if (label != NULL) {
168 len = strlen(label);
169 if (len+1 > sizeof(dp->dmap_label))
170 panic("VFS: map_driver: label too long: %d", len);
171 strlcpy(dp->dmap_label, label, LABEL_MAX);
174 /* Store driver I/O routines based on type of device */
175 switch (style) {
176 case STYLE_DEV:
177 dp->dmap_opcl = gen_opcl;
178 dp->dmap_io = gen_io;
179 break;
180 case STYLE_DEVA:
181 dp->dmap_opcl = gen_opcl;
182 dp->dmap_io = asyn_io;
183 break;
184 case STYLE_TTY:
185 dp->dmap_opcl = tty_opcl;
186 dp->dmap_io = gen_io;
187 break;
188 case STYLE_CTTY:
189 dp->dmap_opcl = ctty_opcl;
190 dp->dmap_io = ctty_io;
191 break;
192 case STYLE_CLONE:
193 dp->dmap_opcl = clone_opcl;
194 dp->dmap_io = gen_io;
195 break;
196 case STYLE_CLONE_A:
197 dp->dmap_opcl = clone_opcl;
198 dp->dmap_io = asyn_io;
199 break;
200 default:
201 return(EINVAL);
204 dp->dmap_driver = proc_nr_e;
205 dp->dmap_flags = flags;
206 dp->dmap_style = style;
208 return(OK);
211 /*===========================================================================*
212 * dmap_unmap_by_endpt *
213 *===========================================================================*/
214 void dmap_unmap_by_endpt(endpoint_t proc_e)
216 /* Lookup driver in dmap table by endpoint and unmap it */
217 int major, r;
219 for (major = 0; major < NR_DEVICES; major++) {
220 if (dmap_driver_match(proc_e, major)) {
221 /* Found driver; overwrite it with a NULL entry */
222 if ((r = map_driver(NULL, major, NONE, 0, 0)) != OK) {
223 printf("VFS: unmapping driver %d for major %d failed:"
224 " %d\n", proc_e, major, r);
230 /*===========================================================================*
231 * map_service *
232 *===========================================================================*/
233 int map_service(struct rprocpub *rpub)
235 /* Map a new service by storing its device driver properties. */
236 int r;
237 struct dmap *fdp, *sdp;
239 /* Not a driver, nothing more to do. */
240 if(rpub->dev_nr == NO_DEV) return(OK);
242 /* Map driver. */
243 r = map_driver(rpub->label, rpub->dev_nr, rpub->endpoint, rpub->dev_style,
244 rpub->dev_flags);
245 if(r != OK) return(r);
247 /* If driver has two major numbers associated, also map the other one. */
248 if(rpub->dev_style2 != STYLE_NDEV) {
249 r = map_driver(rpub->label, rpub->dev_nr+1, rpub->endpoint,
250 rpub->dev_style2, rpub->dev_flags);
251 if(r != OK) return(r);
253 /* To ensure that future dmap lock attempts always lock the same driver
254 * regardless of major number, refer the second dmap lock reference
255 * to the first dmap entry.
257 fdp = get_dmap_by_major(rpub->dev_nr);
258 sdp = get_dmap_by_major(rpub->dev_nr+1);
259 assert(fdp != NULL);
260 assert(sdp != NULL);
261 assert(fdp != sdp);
262 sdp->dmap_lock_ref = &fdp->dmap_lock;
265 return(OK);
268 /*===========================================================================*
269 * init_dmap *
270 *===========================================================================*/
271 void init_dmap()
273 /* Initialize the table with empty device <-> driver mappings. */
274 int i;
275 struct dmap dmap_default = DT_EMPTY;
277 for (i = 0; i < NR_DEVICES; i++)
278 dmap[i] = dmap_default;
281 /*===========================================================================*
282 * init_dmap_locks *
283 *===========================================================================*/
284 void init_dmap_locks()
286 int i;
288 for (i = 0; i < NR_DEVICES; i++) {
289 if (mutex_init(&dmap[i].dmap_lock, NULL) != 0)
290 panic("unable to initialize dmap lock");
291 dmap[i].dmap_lock_ref = &dmap[i].dmap_lock;
295 /*===========================================================================*
296 * dmap_driver_match *
297 *===========================================================================*/
298 int dmap_driver_match(endpoint_t proc, int major)
300 if (major < 0 || major >= NR_DEVICES) return(0);
301 if (dmap[major].dmap_driver != NONE && dmap[major].dmap_driver == proc)
302 return(1);
304 return(0);
307 /*===========================================================================*
308 * dmap_by_major *
309 *===========================================================================*/
310 struct dmap *
311 get_dmap_by_major(int major)
313 if (major < 0 || major >= NR_DEVICES) return(NULL);
314 if (dmap[major].dmap_driver == NONE) return(NULL);
315 return(&dmap[major]);
318 /*===========================================================================*
319 * dmap_endpt_up *
320 *===========================================================================*/
321 void dmap_endpt_up(endpoint_t proc_e, int is_blk)
323 /* A device driver with endpoint proc_e has been restarted. Go tell everyone
324 * that might be blocking on it that this device is 'up'.
327 int major;
328 struct dmap *dp;
329 struct worker_thread *worker;
331 if (proc_e == NONE) return;
333 for (major = 0; major < NR_DEVICES; major++) {
334 if ((dp = get_dmap_by_major(major)) == NULL) continue;
335 if (dp->dmap_driver == proc_e) {
336 if (is_blk) {
337 if (dp->dmap_recovering) {
338 printf("VFS: driver recovery failure for"
339 " major %d\n", major);
340 if (dp->dmap_servicing != NONE) {
341 worker = worker_get(dp->dmap_servicing);
342 worker_stop(worker);
344 dp->dmap_recovering = 0;
345 continue;
347 dp->dmap_recovering = 1;
348 bdev_up(major);
349 dp->dmap_recovering = 0;
350 } else {
351 if (dp->dmap_servicing != NONE) {
352 worker = worker_get(dp->dmap_servicing);
353 worker_stop(worker);
355 cdev_up(major);
361 /*===========================================================================*
362 * get_dmap *
363 *===========================================================================*/
364 struct dmap *get_dmap(endpoint_t proc_e)
366 /* See if 'proc_e' endpoint belongs to a valid dmap entry. If so, return a
367 * pointer */
369 int major;
370 for (major = 0; major < NR_DEVICES; major++)
371 if (dmap_driver_match(proc_e, major))
372 return(&dmap[major]);
374 return(NULL);