iso9660fs: initialize buffer cache
[minix.git] / servers / vfs / dmap.c
blob887c67291b90d046a38dcc087951e49f03bfccb4
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];
82 struct fproc *rfp;
84 /* Only RS can map drivers. */
85 if (who_e != RS_PROC_NR) return(EPERM);
87 label_vir = (vir_bytes) job_m_in.md_label;
88 label_len = (size_t) job_m_in.md_label_len;
89 major = job_m_in.md_major;
90 flags = job_m_in.md_flags;
91 style = job_m_in.md_style;
93 /* Get the label */
94 if (label_len+1 > sizeof(label)) { /* Can we store this label? */
95 printf("VFS: do_mapdriver: label too long\n");
96 return(EINVAL);
98 r = sys_vircopy(who_e, label_vir, SELF, (vir_bytes) label, label_len);
99 if (r != OK) {
100 printf("VFS: do_mapdriver: sys_vircopy failed: %d\n", r);
101 return(EINVAL);
103 label[label_len] = '\0'; /* Terminate label */
105 /* Now we know how the driver is called, fetch its endpoint */
106 r = ds_retrieve_label_endpt(label, &endpoint);
107 if (r != OK) {
108 printf("VFS: do_mapdriver: label '%s' unknown\n", label);
109 return(EINVAL);
112 /* Process is a service */
113 rfp = &fproc[_ENDPOINT_P(endpoint)];
114 rfp->fp_flags |= FP_SRV_PROC;
116 /* Try to update device mapping. */
117 return map_driver(label, major, endpoint, style, flags);
120 /*===========================================================================*
121 * map_driver *
122 *===========================================================================*/
123 int map_driver(label, major, proc_nr_e, style, flags)
124 const char label[LABEL_MAX]; /* name of the driver */
125 int major; /* major number of the device */
126 endpoint_t proc_nr_e; /* process number of the driver */
127 int style; /* style of the device */
128 int flags; /* device flags */
130 /* Add a new device driver mapping in the dmap table. If the proc_nr is set to
131 * NONE, we're supposed to unmap it.
134 int slot, s;
135 size_t len;
136 struct dmap *dp;
138 /* Get pointer to device entry in the dmap table. */
139 if (major < 0 || major >= NR_DEVICES) return(ENODEV);
140 dp = &dmap[major];
142 /* Check if we're supposed to unmap it. */
143 if (proc_nr_e == NONE) {
144 /* Even when a driver is now unmapped and is shortly to be mapped in
145 * due to recovery, invalidate associated filps if they're character
146 * special files. More sophisticated recovery mechanisms which would
147 * reduce the need to invalidate files are possible, but would require
148 * cooperation of the driver and more recovery framework between RS,
149 * VFS, and DS.
151 invalidate_filp_by_char_major(major);
152 dp->dmap_opcl = no_dev;
153 dp->dmap_io = no_dev_io;
154 dp->dmap_driver = NONE;
155 dp->dmap_flags = flags;
156 dp->dmap_lock_ref = &dp->dmap_lock;
157 return(OK);
160 /* Check process number of new driver if it was alive before mapping */
161 s = isokendpt(proc_nr_e, &slot);
162 if (s != OK) {
163 /* This is not a problem only when we force this driver mapping */
164 if (! (flags & DRV_FORCED))
165 return(EINVAL);
168 if (label != NULL) {
169 len = strlen(label);
170 if (len+1 > sizeof(dp->dmap_label))
171 panic("VFS: map_driver: label too long: %d", len);
172 strlcpy(dp->dmap_label, label, LABEL_MAX);
175 /* Store driver I/O routines based on type of device */
176 switch (style) {
177 case STYLE_DEV:
178 dp->dmap_opcl = gen_opcl;
179 dp->dmap_io = gen_io;
180 break;
181 case STYLE_DEVA:
182 dp->dmap_opcl = gen_opcl;
183 dp->dmap_io = asyn_io;
184 break;
185 case STYLE_TTY:
186 dp->dmap_opcl = tty_opcl;
187 dp->dmap_io = gen_io;
188 break;
189 case STYLE_CTTY:
190 dp->dmap_opcl = ctty_opcl;
191 dp->dmap_io = ctty_io;
192 break;
193 case STYLE_CLONE:
194 dp->dmap_opcl = clone_opcl;
195 dp->dmap_io = gen_io;
196 break;
197 case STYLE_CLONE_A:
198 dp->dmap_opcl = clone_opcl;
199 dp->dmap_io = asyn_io;
200 break;
201 default:
202 return(EINVAL);
205 dp->dmap_driver = proc_nr_e;
206 dp->dmap_flags = flags;
207 dp->dmap_style = style;
209 return(OK);
212 /*===========================================================================*
213 * dmap_unmap_by_endpt *
214 *===========================================================================*/
215 void dmap_unmap_by_endpt(endpoint_t proc_e)
217 /* Lookup driver in dmap table by endpoint and unmap it */
218 int major, r;
220 for (major = 0; major < NR_DEVICES; major++) {
221 if (dmap_driver_match(proc_e, major)) {
222 /* Found driver; overwrite it with a NULL entry */
223 if ((r = map_driver(NULL, major, NONE, 0, 0)) != OK) {
224 printf("VFS: unmapping driver %d for major %d failed:"
225 " %d\n", proc_e, major, r);
231 /*===========================================================================*
232 * map_service *
233 *===========================================================================*/
234 int map_service(struct rprocpub *rpub)
236 /* Map a new service by storing its device driver properties. */
237 int r;
238 struct dmap *fdp, *sdp;
239 struct fproc *rfp;
241 /* Process is a service */
242 rfp = &fproc[_ENDPOINT_P(rpub->endpoint)];
243 rfp->fp_flags |= FP_SRV_PROC;
245 /* Not a driver, nothing more to do. */
246 if (rpub->dev_nr == NO_DEV) return(OK);
248 /* Map driver. */
249 r = map_driver(rpub->label, rpub->dev_nr, rpub->endpoint, rpub->dev_style,
250 rpub->dev_flags);
251 if(r != OK) return(r);
253 /* If driver has two major numbers associated, also map the other one. */
254 if(rpub->dev_style2 != STYLE_NDEV) {
255 r = map_driver(rpub->label, rpub->dev_nr+1, rpub->endpoint,
256 rpub->dev_style2, rpub->dev_flags);
257 if(r != OK) return(r);
259 /* To ensure that future dmap lock attempts always lock the same driver
260 * regardless of major number, refer the second dmap lock reference
261 * to the first dmap entry.
263 fdp = get_dmap_by_major(rpub->dev_nr);
264 sdp = get_dmap_by_major(rpub->dev_nr+1);
265 assert(fdp != NULL);
266 assert(sdp != NULL);
267 assert(fdp != sdp);
268 sdp->dmap_lock_ref = &fdp->dmap_lock;
271 return(OK);
274 /*===========================================================================*
275 * init_dmap *
276 *===========================================================================*/
277 void init_dmap()
279 /* Initialize the table with empty device <-> driver mappings. */
280 int i;
281 struct dmap dmap_default = DT_EMPTY;
283 for (i = 0; i < NR_DEVICES; i++)
284 dmap[i] = dmap_default;
287 /*===========================================================================*
288 * init_dmap_locks *
289 *===========================================================================*/
290 void init_dmap_locks()
292 int i;
294 for (i = 0; i < NR_DEVICES; i++) {
295 if (mutex_init(&dmap[i].dmap_lock, NULL) != 0)
296 panic("unable to initialize dmap lock");
297 dmap[i].dmap_lock_ref = &dmap[i].dmap_lock;
301 /*===========================================================================*
302 * dmap_driver_match *
303 *===========================================================================*/
304 int dmap_driver_match(endpoint_t proc, int major)
306 if (major < 0 || major >= NR_DEVICES) return(0);
307 if (dmap[major].dmap_driver != NONE && dmap[major].dmap_driver == proc)
308 return(1);
310 return(0);
313 /*===========================================================================*
314 * dmap_by_major *
315 *===========================================================================*/
316 struct dmap *
317 get_dmap_by_major(int major)
319 if (major < 0 || major >= NR_DEVICES) return(NULL);
320 if (dmap[major].dmap_driver == NONE) return(NULL);
321 return(&dmap[major]);
324 /*===========================================================================*
325 * dmap_endpt_up *
326 *===========================================================================*/
327 void dmap_endpt_up(endpoint_t proc_e, int is_blk)
329 /* A device driver with endpoint proc_e has been restarted. Go tell everyone
330 * that might be blocking on it that this device is 'up'.
333 int major;
334 struct dmap *dp;
335 struct worker_thread *worker;
337 if (proc_e == NONE) return;
339 for (major = 0; major < NR_DEVICES; major++) {
340 if ((dp = get_dmap_by_major(major)) == NULL) continue;
341 if (dp->dmap_driver == proc_e) {
342 if (is_blk) {
343 if (dp->dmap_recovering) {
344 printf("VFS: driver recovery failure for"
345 " major %d\n", major);
346 if (dp->dmap_servicing != NONE) {
347 worker = worker_get(dp->dmap_servicing);
348 worker_stop(worker);
350 dp->dmap_recovering = 0;
351 continue;
353 dp->dmap_recovering = 1;
354 bdev_up(major);
355 dp->dmap_recovering = 0;
356 } else {
357 if (dp->dmap_servicing != NONE) {
358 worker = worker_get(dp->dmap_servicing);
359 worker_stop(worker);
361 cdev_up(major);
367 /*===========================================================================*
368 * get_dmap *
369 *===========================================================================*/
370 struct dmap *get_dmap(endpoint_t proc_e)
372 /* See if 'proc_e' endpoint belongs to a valid dmap entry. If so, return a
373 * pointer */
375 int major;
376 for (major = 0; major < NR_DEVICES; major++)
377 if (dmap_driver_match(proc_e, major))
378 return(&dmap[major]);
380 return(NULL);