xref: /minix/minix/servers/vfs/dmap.c (revision e3b8d4bb)
1433d6423SLionel Sambuc /* This file contains the table with device <-> driver mappings. It also
2433d6423SLionel Sambuc  * contains some routines to dynamically add and/ or remove device drivers
3433d6423SLionel Sambuc  * or change mappings.
4433d6423SLionel Sambuc  */
5433d6423SLionel Sambuc 
6433d6423SLionel Sambuc #include "fs.h"
7433d6423SLionel Sambuc #include <assert.h>
8433d6423SLionel Sambuc #include <string.h>
9433d6423SLionel Sambuc #include <stdlib.h>
10433d6423SLionel Sambuc #include <ctype.h>
11433d6423SLionel Sambuc #include <unistd.h>
12433d6423SLionel Sambuc #include <minix/callnr.h>
13433d6423SLionel Sambuc #include <minix/ds.h>
14433d6423SLionel Sambuc 
15433d6423SLionel Sambuc /* The order of the entries in the table determines the mapping between major
16433d6423SLionel Sambuc  * device numbers and device drivers. Character and block devices
17433d6423SLionel Sambuc  * can be intermixed at random.  The ordering determines the device numbers in
18433d6423SLionel Sambuc  * /dev. Note that the major device numbers used in /dev are NOT the same as
19433d6423SLionel Sambuc  * the process numbers of the device drivers. See <minix/dmap.h> for mappings.
20433d6423SLionel Sambuc  */
21433d6423SLionel Sambuc 
22433d6423SLionel Sambuc struct dmap dmap[NR_DEVICES];
23433d6423SLionel Sambuc 
24433d6423SLionel Sambuc /*===========================================================================*
25433d6423SLionel Sambuc  *				lock_dmap		 		     *
26433d6423SLionel Sambuc  *===========================================================================*/
lock_dmap(struct dmap * dp)27433d6423SLionel Sambuc void lock_dmap(struct dmap *dp)
28433d6423SLionel Sambuc {
29433d6423SLionel Sambuc /* Lock a driver */
30433d6423SLionel Sambuc 	struct worker_thread *org_self;
31433d6423SLionel Sambuc 	int r;
32433d6423SLionel Sambuc 
33433d6423SLionel Sambuc 	assert(dp != NULL);
34433d6423SLionel Sambuc 	assert(dp->dmap_driver != NONE);
35433d6423SLionel Sambuc 
36433d6423SLionel Sambuc 	org_self = worker_suspend();
37433d6423SLionel Sambuc 
38433d6423SLionel Sambuc 	if ((r = mutex_lock(&dp->dmap_lock)) != 0)
39433d6423SLionel Sambuc 		panic("unable to get a lock on dmap: %d\n", r);
40433d6423SLionel Sambuc 
41433d6423SLionel Sambuc 	worker_resume(org_self);
42433d6423SLionel Sambuc }
43433d6423SLionel Sambuc 
44433d6423SLionel Sambuc /*===========================================================================*
45433d6423SLionel Sambuc  *				unlock_dmap		 		     *
46433d6423SLionel Sambuc  *===========================================================================*/
unlock_dmap(struct dmap * dp)47433d6423SLionel Sambuc void unlock_dmap(struct dmap *dp)
48433d6423SLionel Sambuc {
49433d6423SLionel Sambuc /* Unlock a driver */
50433d6423SLionel Sambuc 	int r;
51433d6423SLionel Sambuc 
52433d6423SLionel Sambuc 	assert(dp != NULL);
53433d6423SLionel Sambuc 
54433d6423SLionel Sambuc 	if ((r = mutex_unlock(&dp->dmap_lock)) != 0)
55433d6423SLionel Sambuc 		panic("unable to unlock dmap lock: %d\n", r);
56433d6423SLionel Sambuc }
57433d6423SLionel Sambuc 
58433d6423SLionel Sambuc /*===========================================================================*
59433d6423SLionel Sambuc  *				map_driver		 		     *
60433d6423SLionel Sambuc  *===========================================================================*/
map_driver(const char label[LABEL_MAX],devmajor_t major,endpoint_t proc_nr_e)61433d6423SLionel Sambuc static int map_driver(const char label[LABEL_MAX], devmajor_t major,
62433d6423SLionel Sambuc 	endpoint_t proc_nr_e)
63433d6423SLionel Sambuc {
64433d6423SLionel Sambuc /* Add a new device driver mapping in the dmap table. If the proc_nr is set to
65433d6423SLionel Sambuc  * NONE, we're supposed to unmap it.
66433d6423SLionel Sambuc  */
67433d6423SLionel Sambuc   size_t len;
68433d6423SLionel Sambuc   struct dmap *dp;
69433d6423SLionel Sambuc 
70433d6423SLionel Sambuc   /* Get pointer to device entry in the dmap table. */
71433d6423SLionel Sambuc   if (major < 0 || major >= NR_DEVICES) return(ENODEV);
72433d6423SLionel Sambuc   dp = &dmap[major];
73433d6423SLionel Sambuc 
74433d6423SLionel Sambuc   /* Check if we're supposed to unmap it. */
75433d6423SLionel Sambuc  if (proc_nr_e == NONE) {
76433d6423SLionel Sambuc 	/* Even when a driver is now unmapped and is shortly to be mapped in
77433d6423SLionel Sambuc 	 * due to recovery, invalidate associated filps if they're character
78433d6423SLionel Sambuc 	 * special files. More sophisticated recovery mechanisms which would
79433d6423SLionel Sambuc 	 * reduce the need to invalidate files are possible, but would require
80433d6423SLionel Sambuc 	 * cooperation of the driver and more recovery framework between RS,
81433d6423SLionel Sambuc 	 * VFS, and DS.
82433d6423SLionel Sambuc 	 */
83433d6423SLionel Sambuc 	invalidate_filp_by_char_major(major);
84433d6423SLionel Sambuc 	dp->dmap_driver = NONE;
85433d6423SLionel Sambuc 	return(OK);
86433d6423SLionel Sambuc   }
87433d6423SLionel Sambuc 
88433d6423SLionel Sambuc   if (label != NULL) {
89433d6423SLionel Sambuc 	len = strlen(label);
90433d6423SLionel Sambuc 	if (len+1 > sizeof(dp->dmap_label)) {
913c8950ccSBen Gras 		printf("VFS: map_driver: label too long: %zu\n", len);
92433d6423SLionel Sambuc 		return(EINVAL);
93433d6423SLionel Sambuc 	}
94433d6423SLionel Sambuc 	strlcpy(dp->dmap_label, label, sizeof(dp->dmap_label));
95433d6423SLionel Sambuc   }
96433d6423SLionel Sambuc 
97433d6423SLionel Sambuc   /* Store driver I/O routines based on type of device */
98433d6423SLionel Sambuc   dp->dmap_driver = proc_nr_e;
99433d6423SLionel Sambuc 
100433d6423SLionel Sambuc   return(OK);
101433d6423SLionel Sambuc }
102433d6423SLionel Sambuc 
103433d6423SLionel Sambuc /*===========================================================================*
104433d6423SLionel Sambuc  *				do_mapdriver		 		     *
105433d6423SLionel Sambuc  *===========================================================================*/
do_mapdriver(void)106433d6423SLionel Sambuc int do_mapdriver(void)
107433d6423SLionel Sambuc {
108433d6423SLionel Sambuc /* Create a device->driver mapping. RS will tell us which major is driven by
109433d6423SLionel Sambuc  * this driver, what type of device it is (regular, TTY, asynchronous, clone,
110433d6423SLionel Sambuc  * etc), and its label. This label is registered with DS, and allows us to
111433d6423SLionel Sambuc  * retrieve the driver's endpoint.
112433d6423SLionel Sambuc  */
113*e3b8d4bbSDavid van Moolenbroek   const int *domains;
114181fb1b2SDavid van Moolenbroek   int r, slot, ndomains;
1153b468884SDavid van Moolenbroek   devmajor_t major;
116433d6423SLionel Sambuc   endpoint_t endpoint;
117433d6423SLionel Sambuc   vir_bytes label_vir;
118433d6423SLionel Sambuc   size_t label_len;
119433d6423SLionel Sambuc   char label[LABEL_MAX];
120433d6423SLionel Sambuc   struct fproc *rfp;
121433d6423SLionel Sambuc 
122433d6423SLionel Sambuc   /* Only RS can map drivers. */
123433d6423SLionel Sambuc   if (who_e != RS_PROC_NR) return(EPERM);
124433d6423SLionel Sambuc 
125433d6423SLionel Sambuc   label_vir = job_m_in.m_lsys_vfs_mapdriver.label;
126433d6423SLionel Sambuc   label_len = job_m_in.m_lsys_vfs_mapdriver.labellen;
127433d6423SLionel Sambuc   major = job_m_in.m_lsys_vfs_mapdriver.major;
128181fb1b2SDavid van Moolenbroek   ndomains = job_m_in.m_lsys_vfs_mapdriver.ndomains;
129*e3b8d4bbSDavid van Moolenbroek   domains = job_m_in.m_lsys_vfs_mapdriver.domains;
130433d6423SLionel Sambuc 
131433d6423SLionel Sambuc   /* Get the label */
132433d6423SLionel Sambuc   if (label_len > sizeof(label)) { /* Can we store this label? */
133433d6423SLionel Sambuc 	printf("VFS: do_mapdriver: label too long\n");
134433d6423SLionel Sambuc 	return(EINVAL);
135433d6423SLionel Sambuc   }
136433d6423SLionel Sambuc   r = sys_vircopy(who_e, label_vir, SELF, (vir_bytes) label, label_len,
137433d6423SLionel Sambuc 	CP_FLAG_TRY);
138433d6423SLionel Sambuc   if (r != OK) {
139433d6423SLionel Sambuc 	printf("VFS: do_mapdriver: sys_vircopy failed: %d\n", r);
140433d6423SLionel Sambuc 	return(EINVAL);
141433d6423SLionel Sambuc   }
142433d6423SLionel Sambuc   if (label[label_len-1] != '\0') {
143433d6423SLionel Sambuc 	printf("VFS: do_mapdriver: label not null-terminated\n");
144433d6423SLionel Sambuc 	return(EINVAL);
145433d6423SLionel Sambuc   }
146433d6423SLionel Sambuc 
147433d6423SLionel Sambuc   /* Now we know how the driver is called, fetch its endpoint */
148433d6423SLionel Sambuc   r = ds_retrieve_label_endpt(label, &endpoint);
149433d6423SLionel Sambuc   if (r != OK) {
150433d6423SLionel Sambuc 	printf("VFS: do_mapdriver: label '%s' unknown\n", label);
151433d6423SLionel Sambuc 	return(EINVAL);
152433d6423SLionel Sambuc   }
153433d6423SLionel Sambuc 
154433d6423SLionel Sambuc   /* Process is a service */
155433d6423SLionel Sambuc   if (isokendpt(endpoint, &slot) != OK) {
156433d6423SLionel Sambuc 	printf("VFS: can't map driver to unknown endpoint %d\n", endpoint);
157433d6423SLionel Sambuc 	return(EINVAL);
158433d6423SLionel Sambuc   }
159433d6423SLionel Sambuc   rfp = &fproc[slot];
160433d6423SLionel Sambuc   rfp->fp_flags |= FP_SRV_PROC;
161433d6423SLionel Sambuc 
162433d6423SLionel Sambuc   /* Try to update device mapping. */
163181fb1b2SDavid van Moolenbroek   if (major != NO_DEV) {
164181fb1b2SDavid van Moolenbroek 	if ((r = map_driver(label, major, endpoint)) != OK)
165181fb1b2SDavid van Moolenbroek 		return r;
166181fb1b2SDavid van Moolenbroek   }
167181fb1b2SDavid van Moolenbroek   if (ndomains != 0) {
168*e3b8d4bbSDavid van Moolenbroek 	if ((r = smap_map(label, endpoint, domains, ndomains)) != OK) {
169181fb1b2SDavid van Moolenbroek 		if (major != NO_DEV)
170181fb1b2SDavid van Moolenbroek 			map_driver(NULL, major, NONE); /* undo */
171181fb1b2SDavid van Moolenbroek 		return r;
172181fb1b2SDavid van Moolenbroek 	}
173181fb1b2SDavid van Moolenbroek   }
174181fb1b2SDavid van Moolenbroek   return OK;
175433d6423SLionel Sambuc }
176433d6423SLionel Sambuc 
177433d6423SLionel Sambuc /*===========================================================================*
178433d6423SLionel Sambuc  *				dmap_unmap_by_endpt	 		     *
179433d6423SLionel Sambuc  *===========================================================================*/
dmap_unmap_by_endpt(endpoint_t proc_e)180433d6423SLionel Sambuc void dmap_unmap_by_endpt(endpoint_t proc_e)
181433d6423SLionel Sambuc {
182433d6423SLionel Sambuc /* Lookup driver in dmap table by endpoint and unmap it */
1833b468884SDavid van Moolenbroek   devmajor_t major;
1843b468884SDavid van Moolenbroek   int r;
185433d6423SLionel Sambuc 
186433d6423SLionel Sambuc   for (major = 0; major < NR_DEVICES; major++) {
187433d6423SLionel Sambuc 	if (dmap_driver_match(proc_e, major)) {
188433d6423SLionel Sambuc 		/* Found driver; overwrite it with a NULL entry */
189433d6423SLionel Sambuc 		if ((r = map_driver(NULL, major, NONE)) != OK) {
190433d6423SLionel Sambuc 			printf("VFS: unmapping driver %d for major %d failed:"
191433d6423SLionel Sambuc 				" %d\n", proc_e, major, r);
192433d6423SLionel Sambuc 		}
193433d6423SLionel Sambuc 	}
194433d6423SLionel Sambuc   }
195433d6423SLionel Sambuc }
196433d6423SLionel Sambuc 
197433d6423SLionel Sambuc /*===========================================================================*
198433d6423SLionel Sambuc  *		               map_service				     *
199433d6423SLionel Sambuc  *===========================================================================*/
map_service(struct rprocpub * rpub)200433d6423SLionel Sambuc int map_service(struct rprocpub *rpub)
201433d6423SLionel Sambuc {
202433d6423SLionel Sambuc /* Map a new service by storing its device driver properties. */
203433d6423SLionel Sambuc   int r, slot;
204433d6423SLionel Sambuc   struct fproc *rfp;
205433d6423SLionel Sambuc 
206433d6423SLionel Sambuc   if (IS_RPUB_BOOT_USR(rpub)) return(OK);
207433d6423SLionel Sambuc 
208433d6423SLionel Sambuc   /* Process is a service */
209433d6423SLionel Sambuc   if (isokendpt(rpub->endpoint, &slot) != OK) {
210433d6423SLionel Sambuc 	printf("VFS: can't map service with unknown endpoint %d\n",
211433d6423SLionel Sambuc 		rpub->endpoint);
212433d6423SLionel Sambuc 	return(EINVAL);
213433d6423SLionel Sambuc   }
214433d6423SLionel Sambuc   rfp = &fproc[slot];
215433d6423SLionel Sambuc   rfp->fp_flags |= FP_SRV_PROC;
216433d6423SLionel Sambuc 
217433d6423SLionel Sambuc   /* Not a driver, nothing more to do. */
218433d6423SLionel Sambuc   if (rpub->dev_nr == NO_DEV) return(OK);
219433d6423SLionel Sambuc 
220433d6423SLionel Sambuc   /* Map driver. */
221433d6423SLionel Sambuc   r = map_driver(rpub->label, rpub->dev_nr, rpub->endpoint);
222433d6423SLionel Sambuc   if(r != OK) return(r);
223433d6423SLionel Sambuc 
224433d6423SLionel Sambuc   return(OK);
225433d6423SLionel Sambuc }
226433d6423SLionel Sambuc 
227433d6423SLionel Sambuc /*===========================================================================*
228433d6423SLionel Sambuc  *				init_dmap		 		     *
229433d6423SLionel Sambuc  *===========================================================================*/
init_dmap(void)230433d6423SLionel Sambuc void init_dmap(void)
231433d6423SLionel Sambuc {
232433d6423SLionel Sambuc /* Initialize the device mapping table. */
233433d6423SLionel Sambuc   int i;
234433d6423SLionel Sambuc 
235433d6423SLionel Sambuc   memset(dmap, 0, sizeof(dmap));
236433d6423SLionel Sambuc 
237433d6423SLionel Sambuc   for (i = 0; i < NR_DEVICES; i++) {
238433d6423SLionel Sambuc 	dmap[i].dmap_driver = NONE;
239433d6423SLionel Sambuc 	dmap[i].dmap_servicing = INVALID_THREAD;
240433d6423SLionel Sambuc 	if (mutex_init(&dmap[i].dmap_lock, NULL) != 0)
241433d6423SLionel Sambuc 		panic("unable to initialize dmap lock");
242433d6423SLionel Sambuc   }
243433d6423SLionel Sambuc 
244433d6423SLionel Sambuc   /* CTTY_MAJOR is a special case, which is handled by VFS itself. */
245433d6423SLionel Sambuc   if (map_driver("vfs", CTTY_MAJOR, CTTY_ENDPT) != OK)
246433d6423SLionel Sambuc 	panic("map_driver(CTTY_MAJOR) failed");
247433d6423SLionel Sambuc }
248433d6423SLionel Sambuc 
249433d6423SLionel Sambuc /*===========================================================================*
250433d6423SLionel Sambuc  *				dmap_driver_match	 		     *
251433d6423SLionel Sambuc  *===========================================================================*/
dmap_driver_match(endpoint_t proc,devmajor_t major)2523b468884SDavid van Moolenbroek int dmap_driver_match(endpoint_t proc, devmajor_t major)
253433d6423SLionel Sambuc {
254433d6423SLionel Sambuc   if (major < 0 || major >= NR_DEVICES) return(0);
255433d6423SLionel Sambuc   if (dmap[major].dmap_driver != NONE && dmap[major].dmap_driver == proc)
256433d6423SLionel Sambuc 	return(1);
257433d6423SLionel Sambuc 
258433d6423SLionel Sambuc   return(0);
259433d6423SLionel Sambuc }
260433d6423SLionel Sambuc 
261433d6423SLionel Sambuc /*===========================================================================*
262433d6423SLionel Sambuc  *				dmap_by_major		 		     *
263433d6423SLionel Sambuc  *===========================================================================*/
264433d6423SLionel Sambuc struct dmap *
get_dmap_by_major(devmajor_t major)2653b468884SDavid van Moolenbroek get_dmap_by_major(devmajor_t major)
266433d6423SLionel Sambuc {
267433d6423SLionel Sambuc 	if (major < 0 || major >= NR_DEVICES) return(NULL);
268433d6423SLionel Sambuc 	if (dmap[major].dmap_driver == NONE) return(NULL);
269433d6423SLionel Sambuc 	return(&dmap[major]);
270433d6423SLionel Sambuc }
271433d6423SLionel Sambuc 
272433d6423SLionel Sambuc /*===========================================================================*
273433d6423SLionel Sambuc  *				dmap_endpt_up		 		     *
274433d6423SLionel Sambuc  *===========================================================================*/
dmap_endpt_up(endpoint_t proc_e,int is_blk)275433d6423SLionel Sambuc void dmap_endpt_up(endpoint_t proc_e, int is_blk)
276433d6423SLionel Sambuc {
277433d6423SLionel Sambuc /* A device driver with endpoint proc_e has been restarted. Go tell everyone
278433d6423SLionel Sambuc  * that might be blocking on it that this device is 'up'.
279433d6423SLionel Sambuc  */
2803b468884SDavid van Moolenbroek   devmajor_t major;
281433d6423SLionel Sambuc   struct dmap *dp;
282433d6423SLionel Sambuc   struct worker_thread *worker;
283433d6423SLionel Sambuc 
284433d6423SLionel Sambuc   if (proc_e == NONE) return;
285433d6423SLionel Sambuc 
286433d6423SLionel Sambuc   for (major = 0; major < NR_DEVICES; major++) {
287433d6423SLionel Sambuc 	if ((dp = get_dmap_by_major(major)) == NULL) continue;
288433d6423SLionel Sambuc 	if (dp->dmap_driver == proc_e) {
289433d6423SLionel Sambuc 		if (is_blk) {
290433d6423SLionel Sambuc 			if (dp->dmap_recovering) {
291433d6423SLionel Sambuc 				printf("VFS: driver recovery failure for"
292433d6423SLionel Sambuc 					" major %d\n", major);
293433d6423SLionel Sambuc 				if (dp->dmap_servicing != INVALID_THREAD) {
294433d6423SLionel Sambuc 					worker = worker_get(dp->dmap_servicing);
295433d6423SLionel Sambuc 					worker_stop(worker);
296433d6423SLionel Sambuc 				}
297433d6423SLionel Sambuc 				dp->dmap_recovering = 0;
298433d6423SLionel Sambuc 				continue;
299433d6423SLionel Sambuc 			}
300433d6423SLionel Sambuc 			dp->dmap_recovering = 1;
301433d6423SLionel Sambuc 			bdev_up(major);
302433d6423SLionel Sambuc 			dp->dmap_recovering = 0;
303433d6423SLionel Sambuc 		} else {
304433d6423SLionel Sambuc 			if (dp->dmap_servicing != INVALID_THREAD) {
305433d6423SLionel Sambuc 				worker = worker_get(dp->dmap_servicing);
306433d6423SLionel Sambuc 				worker_stop(worker);
307433d6423SLionel Sambuc 			}
308433d6423SLionel Sambuc 			invalidate_filp_by_char_major(major);
309433d6423SLionel Sambuc 		}
310433d6423SLionel Sambuc 	}
311433d6423SLionel Sambuc   }
312433d6423SLionel Sambuc }
313433d6423SLionel Sambuc 
314433d6423SLionel Sambuc /*===========================================================================*
315433d6423SLionel Sambuc  *				get_dmap		 		     *
316433d6423SLionel Sambuc  *===========================================================================*/
get_dmap_by_endpt(endpoint_t proc_e)317*e3b8d4bbSDavid van Moolenbroek struct dmap *get_dmap_by_endpt(endpoint_t proc_e)
318433d6423SLionel Sambuc {
319433d6423SLionel Sambuc /* See if 'proc_e' endpoint belongs to a valid dmap entry. If so, return a
320433d6423SLionel Sambuc  * pointer */
3213b468884SDavid van Moolenbroek   devmajor_t major;
322433d6423SLionel Sambuc 
323433d6423SLionel Sambuc   for (major = 0; major < NR_DEVICES; major++)
324433d6423SLionel Sambuc 	if (dmap_driver_match(proc_e, major))
325433d6423SLionel Sambuc 		return(&dmap[major]);
326433d6423SLionel Sambuc 
327433d6423SLionel Sambuc   return(NULL);
328433d6423SLionel Sambuc }
329