Remove building with NOCRYPTO option
[minix3.git] / minix / servers / vfs / dmap.c
blob044a7d5c84c29a5b8117a6cd5fa9bc1ba008d91e
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/callnr.h>
13 #include <minix/ds.h>
15 /* The order of the entries in the table determines the mapping between major
16 * device numbers and device drivers. Character and block devices
17 * can be intermixed at random. The ordering determines the device numbers in
18 * /dev. Note that the major device numbers used in /dev are NOT the same as
19 * the process numbers of the device drivers. See <minix/dmap.h> for mappings.
22 struct dmap dmap[NR_DEVICES];
24 /*===========================================================================*
25 * lock_dmap *
26 *===========================================================================*/
27 void lock_dmap(struct dmap *dp)
29 /* Lock a driver */
30 struct worker_thread *org_self;
31 int r;
33 assert(dp != NULL);
34 assert(dp->dmap_driver != NONE);
36 org_self = worker_suspend();
38 if ((r = mutex_lock(&dp->dmap_lock)) != 0)
39 panic("unable to get a lock on dmap: %d\n", r);
41 worker_resume(org_self);
44 /*===========================================================================*
45 * unlock_dmap *
46 *===========================================================================*/
47 void unlock_dmap(struct dmap *dp)
49 /* Unlock a driver */
50 int r;
52 assert(dp != NULL);
54 if ((r = mutex_unlock(&dp->dmap_lock)) != 0)
55 panic("unable to unlock dmap lock: %d\n", r);
58 /*===========================================================================*
59 * map_driver *
60 *===========================================================================*/
61 static int map_driver(const char label[LABEL_MAX], devmajor_t major,
62 endpoint_t proc_nr_e)
64 /* Add a new device driver mapping in the dmap table. If the proc_nr is set to
65 * NONE, we're supposed to unmap it.
67 size_t len;
68 struct dmap *dp;
70 /* Get pointer to device entry in the dmap table. */
71 if (major < 0 || major >= NR_DEVICES) return(ENODEV);
72 dp = &dmap[major];
74 /* Check if we're supposed to unmap it. */
75 if (proc_nr_e == NONE) {
76 /* Even when a driver is now unmapped and is shortly to be mapped in
77 * due to recovery, invalidate associated filps if they're character
78 * special files. More sophisticated recovery mechanisms which would
79 * reduce the need to invalidate files are possible, but would require
80 * cooperation of the driver and more recovery framework between RS,
81 * VFS, and DS.
83 invalidate_filp_by_char_major(major);
84 dp->dmap_driver = NONE;
85 return(OK);
88 if (label != NULL) {
89 len = strlen(label);
90 if (len+1 > sizeof(dp->dmap_label)) {
91 printf("VFS: map_driver: label too long: %zu\n", len);
92 return(EINVAL);
94 strlcpy(dp->dmap_label, label, sizeof(dp->dmap_label));
97 /* Store driver I/O routines based on type of device */
98 dp->dmap_driver = proc_nr_e;
100 return(OK);
103 /*===========================================================================*
104 * do_mapdriver *
105 *===========================================================================*/
106 int do_mapdriver(void)
108 /* Create a device->driver mapping. RS will tell us which major is driven by
109 * this driver, what type of device it is (regular, TTY, asynchronous, clone,
110 * etc), and its label. This label is registered with DS, and allows us to
111 * retrieve the driver's endpoint.
113 const int *domains;
114 int r, slot, ndomains;
115 devmajor_t major;
116 endpoint_t endpoint;
117 vir_bytes label_vir;
118 size_t label_len;
119 char label[LABEL_MAX];
120 struct fproc *rfp;
122 /* Only RS can map drivers. */
123 if (who_e != RS_PROC_NR) return(EPERM);
125 label_vir = job_m_in.m_lsys_vfs_mapdriver.label;
126 label_len = job_m_in.m_lsys_vfs_mapdriver.labellen;
127 major = job_m_in.m_lsys_vfs_mapdriver.major;
128 ndomains = job_m_in.m_lsys_vfs_mapdriver.ndomains;
129 domains = job_m_in.m_lsys_vfs_mapdriver.domains;
131 /* Get the label */
132 if (label_len > sizeof(label)) { /* Can we store this label? */
133 printf("VFS: do_mapdriver: label too long\n");
134 return(EINVAL);
136 r = sys_vircopy(who_e, label_vir, SELF, (vir_bytes) label, label_len,
137 CP_FLAG_TRY);
138 if (r != OK) {
139 printf("VFS: do_mapdriver: sys_vircopy failed: %d\n", r);
140 return(EINVAL);
142 if (label[label_len-1] != '\0') {
143 printf("VFS: do_mapdriver: label not null-terminated\n");
144 return(EINVAL);
147 /* Now we know how the driver is called, fetch its endpoint */
148 r = ds_retrieve_label_endpt(label, &endpoint);
149 if (r != OK) {
150 printf("VFS: do_mapdriver: label '%s' unknown\n", label);
151 return(EINVAL);
154 /* Process is a service */
155 if (isokendpt(endpoint, &slot) != OK) {
156 printf("VFS: can't map driver to unknown endpoint %d\n", endpoint);
157 return(EINVAL);
159 rfp = &fproc[slot];
160 rfp->fp_flags |= FP_SRV_PROC;
162 /* Try to update device mapping. */
163 if (major != NO_DEV) {
164 if ((r = map_driver(label, major, endpoint)) != OK)
165 return r;
167 if (ndomains != 0) {
168 if ((r = smap_map(label, endpoint, domains, ndomains)) != OK) {
169 if (major != NO_DEV)
170 map_driver(NULL, major, NONE); /* undo */
171 return r;
174 return OK;
177 /*===========================================================================*
178 * dmap_unmap_by_endpt *
179 *===========================================================================*/
180 void dmap_unmap_by_endpt(endpoint_t proc_e)
182 /* Lookup driver in dmap table by endpoint and unmap it */
183 devmajor_t major;
184 int r;
186 for (major = 0; major < NR_DEVICES; major++) {
187 if (dmap_driver_match(proc_e, major)) {
188 /* Found driver; overwrite it with a NULL entry */
189 if ((r = map_driver(NULL, major, NONE)) != OK) {
190 printf("VFS: unmapping driver %d for major %d failed:"
191 " %d\n", proc_e, major, r);
197 /*===========================================================================*
198 * map_service *
199 *===========================================================================*/
200 int map_service(struct rprocpub *rpub)
202 /* Map a new service by storing its device driver properties. */
203 int r, slot;
204 struct fproc *rfp;
206 if (IS_RPUB_BOOT_USR(rpub)) return(OK);
208 /* Process is a service */
209 if (isokendpt(rpub->endpoint, &slot) != OK) {
210 printf("VFS: can't map service with unknown endpoint %d\n",
211 rpub->endpoint);
212 return(EINVAL);
214 rfp = &fproc[slot];
215 rfp->fp_flags |= FP_SRV_PROC;
217 /* Not a driver, nothing more to do. */
218 if (rpub->dev_nr == NO_DEV) return(OK);
220 /* Map driver. */
221 r = map_driver(rpub->label, rpub->dev_nr, rpub->endpoint);
222 if(r != OK) return(r);
224 return(OK);
227 /*===========================================================================*
228 * init_dmap *
229 *===========================================================================*/
230 void init_dmap(void)
232 /* Initialize the device mapping table. */
233 int i;
235 memset(dmap, 0, sizeof(dmap));
237 for (i = 0; i < NR_DEVICES; i++) {
238 dmap[i].dmap_driver = NONE;
239 dmap[i].dmap_servicing = INVALID_THREAD;
240 if (mutex_init(&dmap[i].dmap_lock, NULL) != 0)
241 panic("unable to initialize dmap lock");
244 /* CTTY_MAJOR is a special case, which is handled by VFS itself. */
245 if (map_driver("vfs", CTTY_MAJOR, CTTY_ENDPT) != OK)
246 panic("map_driver(CTTY_MAJOR) failed");
249 /*===========================================================================*
250 * dmap_driver_match *
251 *===========================================================================*/
252 int dmap_driver_match(endpoint_t proc, devmajor_t major)
254 if (major < 0 || major >= NR_DEVICES) return(0);
255 if (dmap[major].dmap_driver != NONE && dmap[major].dmap_driver == proc)
256 return(1);
258 return(0);
261 /*===========================================================================*
262 * dmap_by_major *
263 *===========================================================================*/
264 struct dmap *
265 get_dmap_by_major(devmajor_t major)
267 if (major < 0 || major >= NR_DEVICES) return(NULL);
268 if (dmap[major].dmap_driver == NONE) return(NULL);
269 return(&dmap[major]);
272 /*===========================================================================*
273 * dmap_endpt_up *
274 *===========================================================================*/
275 void dmap_endpt_up(endpoint_t proc_e, int is_blk)
277 /* A device driver with endpoint proc_e has been restarted. Go tell everyone
278 * that might be blocking on it that this device is 'up'.
280 devmajor_t major;
281 struct dmap *dp;
282 struct worker_thread *worker;
284 if (proc_e == NONE) return;
286 for (major = 0; major < NR_DEVICES; major++) {
287 if ((dp = get_dmap_by_major(major)) == NULL) continue;
288 if (dp->dmap_driver == proc_e) {
289 if (is_blk) {
290 if (dp->dmap_recovering) {
291 printf("VFS: driver recovery failure for"
292 " major %d\n", major);
293 if (dp->dmap_servicing != INVALID_THREAD) {
294 worker = worker_get(dp->dmap_servicing);
295 worker_stop(worker);
297 dp->dmap_recovering = 0;
298 continue;
300 dp->dmap_recovering = 1;
301 bdev_up(major);
302 dp->dmap_recovering = 0;
303 } else {
304 if (dp->dmap_servicing != INVALID_THREAD) {
305 worker = worker_get(dp->dmap_servicing);
306 worker_stop(worker);
308 invalidate_filp_by_char_major(major);
314 /*===========================================================================*
315 * get_dmap *
316 *===========================================================================*/
317 struct dmap *get_dmap_by_endpt(endpoint_t proc_e)
319 /* See if 'proc_e' endpoint belongs to a valid dmap entry. If so, return a
320 * pointer */
321 devmajor_t major;
323 for (major = 0; major < NR_DEVICES; major++)
324 if (dmap_driver_match(proc_e, major))
325 return(&dmap[major]);
327 return(NULL);