Merge of VFS by Balasz Gerofi with Minix trunk.
[minix3.git] / servers / vfs / device.c
blob914af39b0b8dc57738a608ce36e5e76646a25b59
1 /* When a needed block is not in the cache, it must be fetched from the disk.
2 * Special character files also require I/O. The routines for these are here.
4 * The entry points in this file are:
5 * dev_open: FS opens a device
6 * dev_close: FS closes a device
7 * dev_io: FS does a read or write on a device
8 * dev_status: FS processes callback request alert
9 * gen_opcl: generic call to a task to perform an open/close
10 * gen_io: generic call to a task to perform an I/O operation
11 * no_dev: open/close processing for devices that don't exist
12 * no_dev_io: i/o processing for devices that don't exist
13 * tty_opcl: perform tty-specific processing for open/close
14 * ctty_opcl: perform controlling-tty-specific processing for open/close
15 * ctty_io: perform controlling-tty-specific processing for I/O
16 * do_ioctl: perform the IOCTL system call
17 * do_setsid: perform the SETSID system call (FS side)
20 #include "fs.h"
21 #include <fcntl.h>
22 #include <assert.h>
23 #include <minix/callnr.h>
24 #include <minix/com.h>
25 #include <minix/endpoint.h>
26 #include <minix/ioctl.h>
27 #include "file.h"
28 #include "fproc.h"
30 #include <minix/vfsif.h>
31 #include "vnode.h"
32 #include "vmnt.h"
33 #include "param.h"
35 #define ELEMENTS(a) (sizeof(a)/sizeof((a)[0]))
37 FORWARD _PROTOTYPE( int safe_io_conversion, (endpoint_t,
38 cp_grant_id_t *, int *, cp_grant_id_t *, int, endpoint_t *,
39 void **, int *, vir_bytes, off_t *));
40 FORWARD _PROTOTYPE( void safe_io_cleanup, (cp_grant_id_t, cp_grant_id_t *,
41 int));
43 extern int dmap_size;
44 PRIVATE int dummyproc;
47 /*===========================================================================*
48 * dev_open *
49 *===========================================================================*/
50 PUBLIC int dev_open(dev, proc, flags)
51 dev_t dev; /* device to open */
52 int proc; /* process to open for */
53 int flags; /* mode bits and flags */
55 int major, r;
56 struct dmap *dp;
58 /* Determine the major device number call the device class specific
59 * open/close routine. (This is the only routine that must check the
60 * device number for being in range. All others can trust this check.)
62 major = (dev >> MAJOR) & BYTE;
63 if (major >= NR_DEVICES) major = 0;
64 dp = &dmap[major];
65 if (dp->dmap_driver == NONE)
66 return ENXIO;
67 r = (*dp->dmap_opcl)(DEV_OPEN, dev, proc, flags);
68 if (r == SUSPEND) panic(__FILE__,"suspend on open from", dp->dmap_driver);
69 return(r);
73 /*===========================================================================*
74 * dev_close *
75 *===========================================================================*/
76 PUBLIC void dev_close(dev)
77 dev_t dev; /* device to close */
79 /* See if driver is roughly valid. */
80 if (dmap[(dev >> MAJOR)].dmap_driver == NONE) {
81 return;
83 (void) (*dmap[(dev >> MAJOR) & BYTE].dmap_opcl)(DEV_CLOSE, dev, 0, 0);
86 /*===========================================================================*
87 * suspended_ep *
88 *===========================================================================*/
89 endpoint_t suspended_ep(endpoint_t driver, cp_grant_id_t g)
91 /* A process is suspended on a driver for which FS issued
92 * a grant. Find out which process it was.
94 struct fproc *rfp;
95 for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) {
96 if(rfp->fp_pid == PID_FREE)
97 continue;
98 if(rfp->fp_suspended == SUSPENDED &&
99 rfp->fp_task == -driver && rfp->fp_grant == g) {
100 return rfp->fp_endpoint;
104 return NONE;
107 /*===========================================================================*
108 * dev_status *
109 *===========================================================================*/
110 PUBLIC void dev_status(message *m)
112 message st;
113 int d, get_more = 1;
114 endpoint_t endpt;
116 for(d = 0; d < NR_DEVICES; d++)
117 if (dmap[d].dmap_driver != NONE &&
118 dmap[d].dmap_driver == m->m_source)
119 break;
121 if (d >= NR_DEVICES)
122 return;
124 do {
125 int r;
126 st.m_type = DEV_STATUS;
127 if ((r=sendrec(m->m_source, &st)) != OK) {
128 printf("DEV_STATUS failed to %d: %d\n", m->m_source, r);
129 if (r == EDEADSRCDST) return;
130 if (r == EDSTDIED) return;
131 if (r == ESRCDIED) return;
132 panic(__FILE__,"couldn't sendrec for DEV_STATUS", r);
135 switch(st.m_type) {
136 case DEV_REVIVE:
137 endpt = st.REP_ENDPT;
138 if(endpt == FS_PROC_NR) {
139 endpt = suspended_ep(m->m_source,
140 st.REP_IO_GRANT);
141 if(endpt == NONE) {
142 printf("FS: proc with "
143 "grant %d from %d not found (revive)\n",
144 st.m_source,
145 st.REP_IO_GRANT);
146 continue;
149 revive(endpt, st.REP_STATUS);
150 break;
151 case DEV_IO_READY:
152 select_notified(d, st.DEV_MINOR,
153 st.DEV_SEL_OPS);
154 break;
155 default:
156 printf("FS: unrecognized reply %d to "
157 "DEV_STATUS\n", st.m_type);
158 /* Fall through. */
159 case DEV_NO_STATUS:
160 get_more = 0;
161 break;
163 } while(get_more);
165 return;
168 /*===========================================================================*
169 * safe_io_conversion *
170 *===========================================================================*/
171 PRIVATE int safe_io_conversion(driver, gid, op, gids, gids_size,
172 io_ept, buf, vec_grants, bytes, pos)
173 endpoint_t driver;
174 cp_grant_id_t *gid;
175 int *op;
176 cp_grant_id_t *gids;
177 int gids_size;
178 endpoint_t *io_ept;
179 void **buf;
180 int *vec_grants;
181 vir_bytes bytes;
182 off_t *pos;
184 int access = 0, size;
185 int j;
186 iovec_t *v;
187 static iovec_t new_iovec[NR_IOREQS];
189 /* Number of grants allocated in vector I/O. */
190 *vec_grants = 0;
192 /* Driver can handle it - change request to a safe one. */
194 *gid = GRANT_INVALID;
196 switch(*op) {
197 case DEV_READ:
198 case DEV_WRITE:
199 /* Change to safe op. */
200 *op = *op == DEV_READ ? DEV_READ_S : DEV_WRITE_S;
202 if((*gid=cpf_grant_magic(driver, *io_ept,
203 (vir_bytes) *buf, bytes,
204 *op == DEV_READ_S ? CPF_WRITE : CPF_READ)) < 0) {
205 panic(__FILE__,
206 "cpf_grant_magic of buffer failed\n", NO_NUM);
209 break;
210 case DEV_GATHER:
211 case DEV_SCATTER:
212 /* Change to safe op. */
213 *op = *op == DEV_GATHER ? DEV_GATHER_S : DEV_SCATTER_S;
215 /* Grant access to my new i/o vector. */
216 if((*gid = cpf_grant_direct(driver,
217 (vir_bytes) new_iovec, bytes * sizeof(iovec_t),
218 CPF_READ | CPF_WRITE)) < 0) {
219 panic(__FILE__,
220 "cpf_grant_direct of vector failed", NO_NUM);
222 v = (iovec_t *) *buf;
223 /* Grant access to i/o buffers. */
224 for(j = 0; j < bytes; j++) {
225 if(j >= NR_IOREQS)
226 panic(__FILE__, "vec too big", bytes);
227 new_iovec[j].iov_addr = gids[j] =
228 cpf_grant_direct(driver, (vir_bytes)
229 v[j].iov_addr, v[j].iov_size,
230 *op == DEV_GATHER_S ? CPF_WRITE : CPF_READ);
231 if(!GRANT_VALID(gids[j])) {
232 panic(__FILE__, "grant to iovec buf failed",
233 NO_NUM);
235 new_iovec[j].iov_size = v[j].iov_size;
236 (*vec_grants)++;
239 /* Set user's vector to the new one. */
240 *buf = new_iovec;
241 break;
242 case DEV_IOCTL:
243 *pos = *io_ept; /* Old endpoint in POSITION field. */
244 *op = DEV_IOCTL_S;
245 if(_MINIX_IOCTL_IOR(m_in.REQUEST)) access |= CPF_WRITE;
246 if(_MINIX_IOCTL_IOW(m_in.REQUEST)) access |= CPF_READ;
247 if(_MINIX_IOCTL_BIG(m_in.REQUEST))
248 size = _MINIX_IOCTL_SIZE_BIG(m_in.REQUEST);
249 else
250 size = _MINIX_IOCTL_SIZE(m_in.REQUEST);
253 /* Do this even if no I/O happens with the ioctl, in
254 * order to disambiguate requests with DEV_IOCTL_S.
256 if((*gid=cpf_grant_magic(driver, *io_ept,
257 (vir_bytes) *buf, size, access)) < 0) {
258 panic(__FILE__,
259 "cpf_grant_magic failed (ioctl)\n",
260 NO_NUM);
264 /* If we have converted to a safe operation, I/O
265 * endpoint becomes FS if it wasn't already.
267 if(GRANT_VALID(*gid)) {
268 *io_ept = FS_PROC_NR;
269 return 1;
272 /* Not converted to a safe operation (because there is no
273 * copying involved in this operation).
275 return 0;
278 /*===========================================================================*
279 * safe_io_cleanup *
280 *===========================================================================*/
281 PRIVATE void safe_io_cleanup(gid, gids, gids_size)
282 cp_grant_id_t gid;
283 cp_grant_id_t *gids;
284 int gids_size;
286 /* Free resources (specifically, grants) allocated by safe_io_conversion(). */
287 int j;
289 cpf_revoke(gid);
291 for(j = 0; j < gids_size; j++)
292 cpf_revoke(gids[j]);
294 return;
297 /*===========================================================================*
298 * dev_bio *
299 *===========================================================================*/
300 PUBLIC int dev_bio(op, dev, proc_e, buf, pos, bytes)
301 int op; /* DEV_READ, DEV_WRITE, DEV_IOCTL, etc. */
302 dev_t dev; /* major-minor device number */
303 int proc_e; /* in whose address space is buf? */
304 void *buf; /* virtual address of the buffer */
305 off_t pos; /* byte position */
306 int bytes; /* how many bytes to transfer */
308 /* Read or write from a device. The parameter 'dev' tells which one. */
309 struct dmap *dp;
310 int r, safe;
311 message m;
312 iovec_t *v;
313 cp_grant_id_t gid = GRANT_INVALID;
314 int vec_grants;
316 /* Determine task dmap. */
317 dp = &dmap[(dev >> MAJOR) & BYTE];
319 /* The io vector copying relies on this I/O being for FS itself. */
320 if(proc_e != FS_PROC_NR)
321 panic(__FILE__, "doing dev_bio for non-self", proc_e);
323 for (;;)
325 int op_used;
326 void *buf_used;
327 static cp_grant_id_t gids[NR_IOREQS];
328 cp_grant_id_t gid = GRANT_INVALID;
329 int vec_grants;
331 /* See if driver is roughly valid. */
332 if (dp->dmap_driver == NONE) {
333 printf("FS: dev_io: no driver for dev %x\n", dev);
334 return ENXIO;
337 /* By default, these are right. */
338 m.IO_ENDPT = proc_e;
339 m.ADDRESS = buf;
340 buf_used = buf;
342 /* Convert parameters to 'safe mode'. */
343 op_used = op;
344 safe = safe_io_conversion(dp->dmap_driver, &gid,
345 &op_used, gids, NR_IOREQS, &m.IO_ENDPT, &buf_used,
346 &vec_grants, bytes, &pos);
348 /* Set up rest of the message. */
349 if(safe) m.IO_GRANT = (char *) gid;
351 m.m_type = op_used;
352 m.DEVICE = (dev >> MINOR) & BYTE;
353 m.POSITION = pos;
354 m.COUNT = bytes;
355 m.HIGHPOS = 0;
357 /* Call the task. */
358 (*dp->dmap_io)(dp->dmap_driver, &m);
360 /* As block I/O never SUSPENDs, safe cleanup must be done whether
361 * the I/O succeeded or not.
363 if(safe) safe_io_cleanup(gid, gids, vec_grants);
365 if(dp->dmap_driver == NONE) {
366 /* Driver has vanished. Wait for a new one. */
367 for (;;)
369 r= receive(RS_PROC_NR, &m);
370 if (r != OK)
372 panic(__FILE__,
373 "dev_bio: unable to receive from RS",
376 if (m.m_type == DEVCTL)
378 r= fs_devctl(m.ctl_req, m.dev_nr, m.driver_nr,
379 m.dev_style, m.m_force);
381 else
383 panic(__FILE__,
384 "dev_bio: got message from RS, type",
385 m.m_type);
387 m.m_type= r;
388 r= send(RS_PROC_NR, &m);
389 if (r != OK)
391 panic(__FILE__,
392 "dev_bio: unable to send to RS",
395 if (dp->dmap_driver != NONE)
396 break;
398 printf("dev_bio: trying new driver\n");
399 continue;
402 /* Task has completed. See if call completed. */
403 if (m.REP_STATUS == SUSPEND) {
404 panic(__FILE__, "dev_bio: driver returned SUSPEND", NO_NUM);
407 if(buf != buf_used) {
408 memcpy(buf, buf_used, bytes * sizeof(iovec_t));
411 return(m.REP_STATUS);
415 /*===========================================================================*
416 * dev_io *
417 *===========================================================================*/
418 PUBLIC int dev_io(op, dev, proc_e, buf, pos, bytes, flags)
419 int op; /* DEV_READ, DEV_WRITE, DEV_IOCTL, etc. */
420 dev_t dev; /* major-minor device number */
421 int proc_e; /* in whose address space is buf? */
422 void *buf; /* virtual address of the buffer */
423 off_t pos; /* byte position */
424 int bytes; /* how many bytes to transfer */
425 int flags; /* special flags, like O_NONBLOCK */
427 /* Read or write from a device. The parameter 'dev' tells which one. */
428 struct dmap *dp;
429 message dev_mess;
430 cp_grant_id_t gid = GRANT_INVALID;
431 static cp_grant_id_t gids[NR_IOREQS];
432 int vec_grants = 0, orig_op, safe;
433 void *buf_used;
434 endpoint_t ioproc;
436 /* Determine task dmap. */
437 dp = &dmap[(dev >> MAJOR) & BYTE];
438 orig_op = op;
440 /* See if driver is roughly valid. */
441 if (dp->dmap_driver == NONE) {
442 printf("FS: dev_io: no driver for dev %x\n", dev);
443 return ENXIO;
446 if(isokendpt(dp->dmap_driver, &dummyproc) != OK) {
447 printf("FS: dev_io: old driver for dev %x (%d)\n",
448 dev, dp->dmap_driver);
449 return ENXIO;
452 /* By default, these are right. */
453 dev_mess.IO_ENDPT = proc_e;
454 dev_mess.ADDRESS = buf;
456 /* Convert DEV_* to DEV_*_S variants. */
457 buf_used = buf;
458 safe = safe_io_conversion(dp->dmap_driver, &gid,
459 &op, gids, NR_IOREQS, &dev_mess.IO_ENDPT, &buf_used,
460 &vec_grants, bytes, &pos);
462 if(buf != buf_used)
463 panic(__FILE__,"dev_io: safe_io_conversion changed buffer", NO_NUM);
465 /* If the safe conversion was done, set the ADDRESS to
466 * the grant id.
468 if(safe) dev_mess.IO_GRANT = (char *) gid;
470 /* Set up the rest of the message passed to task. */
471 dev_mess.m_type = op;
472 dev_mess.DEVICE = (dev >> MINOR) & BYTE;
473 dev_mess.POSITION = pos;
474 dev_mess.COUNT = bytes;
475 dev_mess.HIGHPOS = 0;
477 /* This will be used if the i/o is suspended. */
478 ioproc = dev_mess.IO_ENDPT;
480 /* Call the task. */
481 (*dp->dmap_io)(dp->dmap_driver, &dev_mess);
483 if(dp->dmap_driver == NONE) {
484 /* Driver has vanished. */
485 printf("Driver gone?\n");
486 if(safe) safe_io_cleanup(gid, gids, vec_grants);
487 return EIO;
490 /* Task has completed. See if call completed. */
491 if (dev_mess.REP_STATUS == SUSPEND) {
492 if(vec_grants > 0) {
493 panic(__FILE__,"SUSPEND on vectored i/o", NO_NUM);
495 /* fp is uninitialized at init time. */
496 if(!fp)
497 panic(__FILE__,"SUSPEND on NULL fp", NO_NUM);
499 if (flags & O_NONBLOCK) {
500 /* Not supposed to block. */
501 dev_mess.m_type = CANCEL;
502 dev_mess.IO_ENDPT = ioproc;
503 dev_mess.IO_GRANT = (char *) gid;
505 /* This R_BIT/W_BIT check taken from suspend()/unpause()
506 * logic. Mode is expected in the COUNT field.
508 dev_mess.COUNT = 0;
509 if(call_nr == READ) dev_mess.COUNT = R_BIT;
510 else if(call_nr == WRITE) dev_mess.COUNT = W_BIT;
511 dev_mess.DEVICE = (dev >> MINOR) & BYTE;
512 (*dp->dmap_io)(dp->dmap_driver, &dev_mess);
513 if (dev_mess.REP_STATUS == EINTR) dev_mess.REP_STATUS = EAGAIN;
514 } else {
515 /* Suspend user. */
516 suspend(dp->dmap_driver);
517 assert(!GRANT_VALID(fp->fp_grant));
518 fp->fp_grant = gid; /* revoke this when unsuspended. */
519 fp->fp_ioproc = ioproc;
520 return(SUSPEND);
524 /* No suspend, or cancelled suspend, so I/O is over and can be cleaned up. */
525 if(safe) safe_io_cleanup(gid, gids, vec_grants);
527 return(dev_mess.REP_STATUS);
530 /*===========================================================================*
531 * gen_opcl *
532 *===========================================================================*/
533 PUBLIC int gen_opcl(op, dev, proc_e, flags)
534 int op; /* operation, DEV_OPEN or DEV_CLOSE */
535 dev_t dev; /* device to open or close */
536 int proc_e; /* process to open/close for */
537 int flags; /* mode bits and flags */
539 /* Called from the dmap struct in table.c on opens & closes of special files.*/
540 struct dmap *dp;
541 message dev_mess;
543 /* Determine task dmap. */
544 dp = &dmap[(dev >> MAJOR) & BYTE];
546 dev_mess.m_type = op;
547 dev_mess.DEVICE = (dev >> MINOR) & BYTE;
548 dev_mess.IO_ENDPT = proc_e;
549 dev_mess.COUNT = flags;
551 if (dp->dmap_driver == NONE) {
552 printf("FS: gen_opcl: no driver for dev %x\n", dev);
553 return ENXIO;
556 /* Call the task. */
557 (*dp->dmap_io)(dp->dmap_driver, &dev_mess);
559 return(dev_mess.REP_STATUS);
562 /*===========================================================================*
563 * tty_opcl *
564 *===========================================================================*/
565 PUBLIC int tty_opcl(op, dev, proc_e, flags)
566 int op; /* operation, DEV_OPEN or DEV_CLOSE */
567 dev_t dev; /* device to open or close */
568 int proc_e; /* process to open/close for */
569 int flags; /* mode bits and flags */
571 /* This procedure is called from the dmap struct on tty open/close. */
573 int r;
574 register struct fproc *rfp;
576 /* Add O_NOCTTY to the flags if this process is not a session leader, or
577 * if it already has a controlling tty, or if it is someone elses
578 * controlling tty.
580 if (!fp->fp_sesldr || fp->fp_tty != 0) {
581 flags |= O_NOCTTY;
582 } else {
583 for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) {
584 if(rfp->fp_pid == PID_FREE) continue;
585 if (rfp->fp_tty == dev) flags |= O_NOCTTY;
589 r = gen_opcl(op, dev, proc_e, flags);
591 /* Did this call make the tty the controlling tty? */
592 if (r == 1) {
593 fp->fp_tty = dev;
594 r = OK;
596 return(r);
599 /*===========================================================================*
600 * ctty_opcl *
601 *===========================================================================*/
602 PUBLIC int ctty_opcl(op, dev, proc_e, flags)
603 int op; /* operation, DEV_OPEN or DEV_CLOSE */
604 dev_t dev; /* device to open or close */
605 int proc_e; /* process to open/close for */
606 int flags; /* mode bits and flags */
608 /* This procedure is called from the dmap struct in table.c on opening/closing
609 * /dev/tty, the magic device that translates to the controlling tty.
612 return(fp->fp_tty == 0 ? ENXIO : OK);
615 /*===========================================================================*
616 * pm_setsid *
617 *===========================================================================*/
618 PUBLIC void pm_setsid(proc_e)
619 int proc_e;
621 /* Perform the FS side of the SETSID call, i.e. get rid of the controlling
622 * terminal of a process, and make the process a session leader.
624 register struct fproc *rfp;
625 int slot;
627 /* Make the process a session leader with no controlling tty. */
628 okendpt(proc_e, &slot);
629 rfp = &fproc[slot];
630 rfp->fp_sesldr = TRUE;
631 rfp->fp_tty = 0;
634 /*===========================================================================*
635 * do_ioctl *
636 *===========================================================================*/
637 PUBLIC int do_ioctl()
639 /* Perform the ioctl(ls_fd, request, argx) system call (uses m2 fmt). */
641 struct filp *f;
642 register struct vnode *vp;
643 dev_t dev;
645 if ( (f = get_filp(m_in.ls_fd)) == NIL_FILP) return(err_code);
646 vp = f->filp_vno; /* get vnode pointer */
647 if ( (vp->v_mode & I_TYPE) != I_CHAR_SPECIAL
648 && (vp->v_mode & I_TYPE) != I_BLOCK_SPECIAL) return(ENOTTY);
649 dev = (dev_t) vp->v_sdev;
651 return(dev_io(DEV_IOCTL, dev, who_e, m_in.ADDRESS, 0L,
652 m_in.REQUEST, f->filp_flags));
655 /*===========================================================================*
656 * gen_io *
657 *===========================================================================*/
658 PUBLIC int gen_io(task_nr, mess_ptr)
659 int task_nr; /* which task to call */
660 message *mess_ptr; /* pointer to message for task */
662 /* All file system I/O ultimately comes down to I/O on major/minor device
663 * pairs. These lead to calls on the following routines via the dmap table.
666 int r, proc_e;
668 proc_e = mess_ptr->IO_ENDPT;
670 r = sendrec(task_nr, mess_ptr);
671 if (r != OK) {
672 if (r == EDEADSRCDST || r == EDSTDIED || r == ESRCDIED) {
673 printf("fs: dead driver %d\n", task_nr);
674 dmap_unmap_by_endpt(task_nr);
675 return r;
677 if (r == ELOCKED) {
678 printf("fs: ELOCKED talking to %d\n", task_nr);
679 return r;
681 panic(__FILE__,"call_task: can't send/receive", r);
684 /* Did the process we did the sendrec() for get a result? */
685 if (mess_ptr->REP_ENDPT != proc_e) {
686 printf(
687 "fs: strange device reply from %d, type = %d, proc = %d (not %d) (2) ignored\n",
688 mess_ptr->m_source,
689 mess_ptr->m_type,
690 proc_e,
691 mess_ptr->REP_ENDPT);
692 return EIO;
695 return OK;
698 /*===========================================================================*
699 * ctty_io *
700 *===========================================================================*/
701 PUBLIC int ctty_io(task_nr, mess_ptr)
702 int task_nr; /* not used - for compatibility with dmap_t */
703 message *mess_ptr; /* pointer to message for task */
705 /* This routine is only called for one device, namely /dev/tty. Its job
706 * is to change the message to use the controlling terminal, instead of the
707 * major/minor pair for /dev/tty itself.
710 struct dmap *dp;
712 if (fp->fp_tty == 0) {
713 /* No controlling tty present anymore, return an I/O error. */
714 mess_ptr->REP_STATUS = EIO;
715 } else {
716 /* Substitute the controlling terminal device. */
717 dp = &dmap[(fp->fp_tty >> MAJOR) & BYTE];
718 mess_ptr->DEVICE = (fp->fp_tty >> MINOR) & BYTE;
720 if (dp->dmap_driver == NONE) {
721 printf("FS: ctty_io: no driver for dev\n");
722 return EIO;
725 if(isokendpt(dp->dmap_driver, &dummyproc) != OK) {
726 printf("FS: ctty_io: old driver %d\n",
727 dp->dmap_driver);
728 return EIO;
731 (*dp->dmap_io)(dp->dmap_driver, mess_ptr);
733 return OK;
737 /*===========================================================================*
738 * no_dev *
739 *===========================================================================*/
740 PUBLIC int no_dev(op, dev, proc, flags)
741 int op; /* operation, DEV_OPEN or DEV_CLOSE */
742 dev_t dev; /* device to open or close */
743 int proc; /* process to open/close for */
744 int flags; /* mode bits and flags */
746 /* Called when opening a nonexistent device. */
747 return(ENODEV);
750 /*===========================================================================*
751 * no_dev_io *
752 *===========================================================================*/
753 PUBLIC int no_dev_io(int proc, message *m)
755 /* Called when doing i/o on a nonexistent device. */
756 printf("VFS: I/O on unmapped device number\n");
757 return EIO;
762 /*===========================================================================*
763 * clone_opcl *
764 *===========================================================================*/
765 PUBLIC int clone_opcl(op, dev, proc_e, flags)
766 int op; /* operation, DEV_OPEN or DEV_CLOSE */
767 dev_t dev; /* device to open or close */
768 int proc_e; /* process to open/close for */
769 int flags; /* mode bits and flags */
771 /* Some devices need special processing upon open. Such a device is "cloned",
772 * i.e. on a succesful open it is replaced by a new device with a new unique
773 * minor device number. This new device number identifies a new object (such
774 * as a new network connection) that has been allocated within a task.
776 struct dmap *dp;
777 int r, minor;
778 message dev_mess;
780 /* Determine task dmap. */
781 dp = &dmap[(dev >> MAJOR) & BYTE];
782 minor = (dev >> MINOR) & BYTE;
784 dev_mess.m_type = op;
785 dev_mess.DEVICE = minor;
786 dev_mess.IO_ENDPT = proc_e;
787 dev_mess.COUNT = flags;
790 if (dp->dmap_driver == NONE) {
791 printf("FS: clone_opcl: no driver for dev %x\n", dev);
792 return ENXIO;
795 if(isokendpt(dp->dmap_driver, &dummyproc) != OK) {
796 printf("FS: clone_opcl: old driver for dev %x (%d)\n",
797 dev, dp->dmap_driver);
798 return ENXIO;
801 /* Call the task. */
802 r= (*dp->dmap_io)(dp->dmap_driver, &dev_mess);
803 if (r != OK)
804 return r;
806 if (op == DEV_OPEN && dev_mess.REP_STATUS >= 0) {
807 if (dev_mess.REP_STATUS != minor) {
808 struct vnode *vp;
809 struct vmnt *vmp;
811 struct clone_opcl_req req;
812 struct node_details res;
813 /* A new minor device number has been returned.
814 * Request root FS to create a temporary device file to hold it.
817 /* Device number of the new device. */
818 dev = (dev & ~(BYTE << MINOR)) | (dev_mess.REP_STATUS << MINOR);
820 /* Fill in request */
821 req.fs_e = ROOT_FS_E;
822 req.dev = dev;
824 /* Issue request */
825 if ((r = req_clone_opcl(&req, &res)) != OK) {
826 (void) clone_opcl(DEV_CLOSE, dev, proc_e, 0);
827 return r;
830 /* Drop old node and use the new values */
831 vp = fp->fp_filp[m_in.fd]->filp_vno;
833 put_vnode(vp);
834 if ((vp = get_free_vnode()) == NIL_VNODE) {
835 printf("VFSclone_opcl: failed to get a free vnode..\n");
836 vp = fp->fp_filp[m_in.fd]->filp_vno;
839 vp->v_fs_e = res.fs_e;
840 if ((vmp = find_vmnt(vp->v_fs_e)) == NIL_VMNT)
841 printf("VFSclone_opcl: no vmnt found\n");
843 vp->v_vmnt = vmp;
844 vp->v_dev = vmp->m_dev;
846 vp->v_inode_nr = res.inode_nr;
847 vp->v_mode = res.fmode;
848 vp->v_sdev = dev;
849 vp->v_count = 1;
850 fp->fp_filp[m_in.fd]->filp_vno = vp;
852 dev_mess.REP_STATUS = OK;
854 return(dev_mess.REP_STATUS);
857 /*===========================================================================*
858 * dev_up *
859 *===========================================================================*/
860 PUBLIC void dev_up(int maj)
862 /* A new device driver has been mapped in. This function
863 * checks if any filesystems are mounted on it, and if so,
864 * dev_open()s them so the filesystem can be reused.
866 struct filp *fp;
867 struct vmnt *vmp;
868 int r, new_driver_e;
869 message m;
871 /* Open a device once for every filp that's opened on it,
872 * and once for every filesystem mounted from it.
874 new_driver_e = dmap[maj].dmap_driver;
876 for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp) {
877 int minor;
878 if (vmp->m_dev == NO_DEV) continue;
879 if ( ((vmp->m_dev >> MAJOR) & BYTE) != maj) continue;
880 minor = ((vmp->m_dev >> MINOR) & BYTE);
882 printf("VFS: re-opening dev: %d/%d\n", maj, minor);
884 if ((r = dev_open(vmp->m_dev, FS_PROC_NR,
885 vmp->m_flags ? R_BIT : (R_BIT|W_BIT))) != OK) {
886 printf("VFS: mounted dev %d/%d re-open failed: %d.\n",
887 maj, minor, r);
890 /* Send new driver endpoint */
891 printf("VFS: sending new dirver for dev: %d, endpoint: %d, FS_e: %d\n",
892 vmp->m_dev, new_driver_e, vmp->m_fs_e);
894 if (OK != req_newdriver(vmp->m_fs_e, vmp->m_dev, new_driver_e))
895 printf("VFSdev_up: error sending new driver endpoint. FS_e: %d req_nr: %d\n",
896 vmp->m_fs_e, REQ_NEW_DRIVER);
897 else
898 vmp->m_driver_e = new_driver_e;
901 for (fp = filp; fp < &filp[NR_FILPS]; fp++) {
902 struct vnode *vp;
903 int minor;
905 if(fp->filp_count < 1 || !(vp = fp->filp_vno)) continue;
906 if(((vp->v_sdev >> MAJOR) & BYTE) != maj) continue;
907 if(!(vp->v_mode & (I_BLOCK_SPECIAL|I_CHAR_SPECIAL))) continue;
909 minor = ((vp->v_sdev >> MINOR) & BYTE);
911 printf("VFS: reopening special %d/%d..\n", maj, minor);
913 if((r = dev_open(vp->v_sdev, FS_PROC_NR,
914 vp->v_mode & (R_BIT|W_BIT))) != OK) {
915 int n;
916 /* This function will set the fp_filp[]s of processes
917 * holding that fp to NULL, but _not_ clear
918 * fp_filp_inuse, so that fd can't be recycled until
919 * it's close()d.
921 n = inval_filp(fp);
922 if(n != fp->filp_count)
923 printf("VFS: warning: invalidate/count "
924 "discrepancy (%d, %d)\n", n, fp->filp_count);
925 fp->filp_count = 0;
926 printf("VFS: file on dev %d/%d re-open failed: %d; "
927 "invalidated %d fd's.\n", maj, minor, r, n);
931 return;