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)
23 #include <minix/callnr.h>
24 #include <minix/com.h>
25 #include <minix/endpoint.h>
26 #include <minix/ioctl.h>
27 #include <minix/u64.h>
30 #include <minix/vfsif.h>
35 #define ELEMENTS(a) (sizeof(a)/sizeof((a)[0]))
37 FORWARD
_PROTOTYPE( int safe_io_conversion
, (endpoint_t
, cp_grant_id_t
*,
38 int *, cp_grant_id_t
*, int,
39 endpoint_t
*, void **, int *,
40 vir_bytes
, u32_t
*) );
41 FORWARD
_PROTOTYPE( void safe_io_cleanup
, (cp_grant_id_t
, cp_grant_id_t
*,
43 FORWARD
_PROTOTYPE( void restart_reopen
, (int maj
) );
46 PRIVATE
int dummyproc
;
49 /*===========================================================================*
51 *===========================================================================*/
52 PUBLIC
int dev_open(dev
, proc
, flags
)
53 dev_t dev
; /* device to open */
54 int proc
; /* process to open for */
55 int flags
; /* mode bits and flags */
60 /* Determine the major device number call the device class specific
61 * open/close routine. (This is the only routine that must check the
62 * device number for being in range. All others can trust this check.)
64 major
= (dev
>> MAJOR
) & BYTE
;
65 if (major
>= NR_DEVICES
) major
= 0;
67 if (dp
->dmap_driver
== NONE
) return(ENXIO
);
68 r
= (*dp
->dmap_opcl
)(DEV_OPEN
, dev
, proc
, flags
);
73 /*===========================================================================*
75 *===========================================================================*/
76 PUBLIC
int dev_reopen(dev
, filp_no
, flags
)
77 dev_t dev
; /* device to open */
78 int filp_no
; /* filp to reopen for */
79 int flags
; /* mode bits and flags */
84 /* Determine the major device number call the device class specific
85 * open/close routine. (This is the only routine that must check the
86 * device number for being in range. All others can trust this check.)
88 major
= (dev
>> MAJOR
) & BYTE
;
89 if (major
>= NR_DEVICES
) major
= 0;
91 if (dp
->dmap_driver
== NONE
) return(ENXIO
);
92 r
= (*dp
->dmap_opcl
)(DEV_REOPEN
, dev
, filp_no
, flags
);
93 if (r
== OK
) panic(__FILE__
,"OK on reopen from", dp
->dmap_driver
);
94 if (r
== SUSPEND
) r
= OK
;
99 /*===========================================================================*
101 *===========================================================================*/
102 PUBLIC
int dev_close(dev
, filp_no
)
103 dev_t dev
; /* device to close */
108 /* See if driver is roughly valid. */
109 if (dmap
[(dev
>> MAJOR
)].dmap_driver
== NONE
) return(ENXIO
);
110 r
= (*dmap
[(dev
>> MAJOR
) & BYTE
].dmap_opcl
)(DEV_CLOSE
, dev
, filp_no
, 0);
115 /*===========================================================================*
117 *===========================================================================*/
118 endpoint_t
suspended_ep(endpoint_t driver
, cp_grant_id_t g
)
120 /* A process is suspended on a driver for which FS issued
121 * a grant. Find out which process it was.
124 for (rfp
= &fproc
[0]; rfp
< &fproc
[NR_PROCS
]; rfp
++) {
125 if(rfp
->fp_pid
== PID_FREE
) continue;
126 if(rfp
->fp_blocked_on
== FP_BLOCKED_ON_OTHER
&&
127 rfp
->fp_task
== driver
&& rfp
->fp_grant
== g
)
128 return rfp
->fp_endpoint
;
135 /*===========================================================================*
137 *===========================================================================*/
138 PUBLIC
void dev_status(message
*m
)
144 for(d
= 0; d
< NR_DEVICES
; d
++)
145 if (dmap
[d
].dmap_driver
!= NONE
&& dmap
[d
].dmap_driver
== m
->m_source
)
148 if (d
>= NR_DEVICES
) return;
149 if (dmap
[d
].dmap_async_driver
) {
150 printf("dev_status: not doing dev_status for async driver %d\n",
157 st
.m_type
= DEV_STATUS
;
158 if ((r
= sendrec(m
->m_source
, &st
)) != OK
) {
159 printf("DEV_STATUS failed to %d: %d\n", m
->m_source
, r
);
160 if (r
== EDEADSRCDST
) return;
161 if (r
== EDSTDIED
) return;
162 if (r
== ESRCDIED
) return;
163 panic(__FILE__
,"couldn't sendrec for DEV_STATUS", r
);
168 endpt
= st
.REP_ENDPT
;
169 if(endpt
== FS_PROC_NR
) {
170 endpt
= suspended_ep(m
->m_source
,
173 printf("FS: proc with grant %d"
174 " from %d not found (revive)\n",
175 st
.REP_IO_GRANT
, st
.m_source
);
179 revive(endpt
, st
.REP_STATUS
);
182 select_notified(d
, st
.DEV_MINOR
,
186 printf("FS: unrecognized reply %d to "
187 "DEV_STATUS\n", st
.m_type
);
199 /*===========================================================================*
200 * safe_io_conversion *
201 *===========================================================================*/
202 PRIVATE
int safe_io_conversion(driver
, gid
, op
, gids
, gids_size
,
203 io_ept
, buf
, vec_grants
, bytes
, pos_lo
)
215 int access
= 0, size
, j
;
217 static iovec_t new_iovec
[NR_IOREQS
];
219 /* Number of grants allocated in vector I/O. */
222 /* Driver can handle it - change request to a safe one. */
223 *gid
= GRANT_INVALID
;
228 /* Change to safe op. */
229 *op
= *op
== VFS_DEV_READ
? DEV_READ_S
: DEV_WRITE_S
;
231 *gid
= cpf_grant_magic(driver
, *io_ept
, (vir_bytes
) *buf
, bytes
,
232 *op
== DEV_READ_S
? CPF_WRITE
: CPF_READ
);
234 panic(__FILE__
, "cpf_grant_magic of buffer failed\n", NO_NUM
);
237 case VFS_DEV_SCATTER
:
238 /* Change to safe op. */
239 *op
= *op
== VFS_DEV_GATHER
? DEV_GATHER_S
: DEV_SCATTER_S
;
241 /* Grant access to my new i/o vector. */
242 *gid
= cpf_grant_direct(driver
, (vir_bytes
) new_iovec
,
243 bytes
* sizeof(iovec_t
), CPF_READ
|CPF_WRITE
);
245 panic(__FILE__
, "cpf_grant_direct of vector failed", NO_NUM
);
247 v
= (iovec_t
*) *buf
;
248 /* Grant access to i/o buffers. */
249 for(j
= 0; j
< bytes
; j
++) {
250 if(j
>= NR_IOREQS
) panic(__FILE__
, "vec too big", bytes
);
252 new_iovec
[j
].iov_addr
=
254 cpf_grant_direct(driver
, (vir_bytes
) v
[j
].iov_addr
, v
[j
].iov_size
,
255 *op
== DEV_GATHER_S
? CPF_WRITE
: CPF_READ
);
257 if(!GRANT_VALID(gids
[j
]))
258 panic(__FILE__
, "grant to iovec buf failed", NO_NUM
);
260 new_iovec
[j
].iov_size
= v
[j
].iov_size
;
264 /* Set user's vector to the new one. */
268 *pos_lo
= *io_ept
; /* Old endpoint in POSITION field. */
270 if(_MINIX_IOCTL_IOR(m_in
.REQUEST
)) access
|= CPF_WRITE
;
271 if(_MINIX_IOCTL_IOW(m_in
.REQUEST
)) access
|= CPF_READ
;
272 if(_MINIX_IOCTL_BIG(m_in
.REQUEST
))
273 size
= _MINIX_IOCTL_SIZE_BIG(m_in
.REQUEST
);
275 size
= _MINIX_IOCTL_SIZE(m_in
.REQUEST
);
278 /* Do this even if no I/O happens with the ioctl, in
279 * order to disambiguate requests with DEV_IOCTL_S.
281 *gid
= cpf_grant_magic(driver
, *io_ept
, (vir_bytes
) *buf
, size
,
284 panic(__FILE__
, "cpf_grant_magic failed (ioctl)\n", NO_NUM
);
291 panic(__FILE__
,"safe_io_conversion: unknown operation", *op
);
294 /* If we have converted to a safe operation, I/O
295 * endpoint becomes FS if it wasn't already.
297 if(GRANT_VALID(*gid
)) {
298 *io_ept
= FS_PROC_NR
;
302 /* Not converted to a safe operation (because there is no
303 * copying involved in this operation).
308 /*===========================================================================*
310 *===========================================================================*/
311 PRIVATE
void safe_io_cleanup(gid
, gids
, gids_size
)
316 /* Free resources (specifically, grants) allocated by safe_io_conversion(). */
320 for(j
= 0; j
< gids_size
; j
++)
325 /*===========================================================================*
327 *===========================================================================*/
328 PUBLIC
int dev_io(op
, dev
, proc_e
, buf
, pos
, bytes
, flags
, suspend_reopen
)
329 int op
; /* DEV_READ, DEV_WRITE, DEV_IOCTL, etc. */
330 dev_t dev
; /* major-minor device number */
331 int proc_e
; /* in whose address space is buf? */
332 void *buf
; /* virtual address of the buffer */
333 u64_t pos
; /* byte position */
334 int bytes
; /* how many bytes to transfer */
335 int flags
; /* special flags, like O_NONBLOCK */
336 int suspend_reopen
; /* Just suspend the process */
338 /* Read or write from a device. The parameter 'dev' tells which one. */
340 u32_t pos_lo
, pos_high
;
342 cp_grant_id_t gid
= GRANT_INVALID
;
343 static cp_grant_id_t gids
[NR_IOREQS
];
344 int vec_grants
= 0, orig_op
, safe
;
349 pos_high
= ex64hi(pos
);
351 /* Determine task dmap. */
352 dp
= &dmap
[(dev
>> MAJOR
) & BYTE
];
355 /* See if driver is roughly valid. */
356 if (dp
->dmap_driver
== NONE
) {
357 printf("FS: dev_io: no driver for dev %x\n", dev
);
361 if (suspend_reopen
) {
363 fp
->fp_grant
= GRANT_INVALID
;
364 fp
->fp_ioproc
= NONE
;
365 wait_for(dp
->dmap_driver
);
366 fp
->fp_flags
|= SUSP_REOPEN
;
370 if(isokendpt(dp
->dmap_driver
, &dummyproc
) != OK
) {
371 printf("FS: dev_io: old driver for dev %x (%d)\n",dev
,dp
->dmap_driver
);
375 /* By default, these are right. */
376 dev_mess
.IO_ENDPT
= proc_e
;
377 dev_mess
.ADDRESS
= buf
;
379 /* Convert DEV_* to DEV_*_S variants. */
381 safe
= safe_io_conversion(dp
->dmap_driver
, &gid
, &op
, gids
, NR_IOREQS
,
382 (endpoint_t
*) &dev_mess
.IO_ENDPT
, &buf_used
,
383 &vec_grants
, bytes
, &pos_lo
);
386 panic(__FILE__
,"dev_io: safe_io_conversion changed buffer", NO_NUM
);
388 /* If the safe conversion was done, set the ADDRESS to
391 if(safe
) dev_mess
.IO_GRANT
= (char *) gid
;
393 /* Set up the rest of the message passed to task. */
394 dev_mess
.m_type
= op
;
395 dev_mess
.DEVICE
= (dev
>> MINOR
) & BYTE
;
396 dev_mess
.POSITION
= pos_lo
;
397 dev_mess
.COUNT
= bytes
;
398 dev_mess
.HIGHPOS
= pos_high
;
400 /* This will be used if the i/o is suspended. */
401 ioproc
= dev_mess
.IO_ENDPT
;
404 (*dp
->dmap_io
)(dp
->dmap_driver
, &dev_mess
);
406 if(dp
->dmap_driver
== NONE
) {
407 /* Driver has vanished. */
408 printf("Driver gone?\n");
409 if(safe
) safe_io_cleanup(gid
, gids
, vec_grants
);
413 /* Task has completed. See if call completed. */
414 if (dev_mess
.REP_STATUS
== SUSPEND
) {
415 if(vec_grants
> 0) panic(__FILE__
,"SUSPEND on vectored i/o", NO_NUM
);
417 /* fp is uninitialized at init time. */
418 if(!fp
) panic(__FILE__
,"SUSPEND on NULL fp", NO_NUM
);
420 if ((flags
& O_NONBLOCK
) && !dp
->dmap_async_driver
) {
421 /* Not supposed to block. */
422 dev_mess
.m_type
= CANCEL
;
423 dev_mess
.IO_ENDPT
= ioproc
;
424 dev_mess
.IO_GRANT
= (char *) gid
;
426 /* This R_BIT/W_BIT check taken from suspend()/unpause()
427 * logic. Mode is expected in the COUNT field.
430 if (call_nr
== READ
) dev_mess
.COUNT
= R_BIT
;
431 else if (call_nr
== WRITE
) dev_mess
.COUNT
= W_BIT
;
432 dev_mess
.DEVICE
= (dev
>> MINOR
) & BYTE
;
433 (*dp
->dmap_io
)(dp
->dmap_driver
, &dev_mess
);
434 if (dev_mess
.REP_STATUS
== EINTR
) dev_mess
.REP_STATUS
= EAGAIN
;
436 /* select() will do suspending itself. */
437 if(op
!= DEV_SELECT
) {
439 wait_for(dp
->dmap_driver
);
441 assert(!GRANT_VALID(fp
->fp_grant
));
442 fp
->fp_grant
= gid
; /* revoke this when unsuspended. */
443 fp
->fp_ioproc
= ioproc
;
445 if (flags
& O_NONBLOCK
) {
446 /* Not supposed to block, send cancel message */
447 dev_mess
.m_type
= CANCEL
;
448 dev_mess
.IO_ENDPT
= ioproc
;
449 dev_mess
.IO_GRANT
= (char *) gid
;
451 /* This R_BIT/W_BIT check taken from suspend()/unpause()
452 * logic. Mode is expected in the COUNT field.
455 if(call_nr
== READ
) dev_mess
.COUNT
= R_BIT
;
456 else if(call_nr
== WRITE
) dev_mess
.COUNT
= W_BIT
;
457 dev_mess
.DEVICE
= (dev
>> MINOR
) & BYTE
;
458 (*dp
->dmap_io
)(dp
->dmap_driver
, &dev_mess
);
460 /* Should do something about EINTR -> EAGAIN mapping */
466 /* No suspend, or cancelled suspend, so I/O is over and can be cleaned up. */
467 if(safe
) safe_io_cleanup(gid
, gids
, vec_grants
);
469 return(dev_mess
.REP_STATUS
);
472 /*===========================================================================*
474 *===========================================================================*/
475 PUBLIC
int gen_opcl(op
, dev
, proc_e
, flags
)
476 int op
; /* operation, DEV_OPEN or DEV_CLOSE */
477 dev_t dev
; /* device to open or close */
478 int proc_e
; /* process to open/close for */
479 int flags
; /* mode bits and flags */
481 /* Called from the dmap struct in table.c on opens & closes of special files.*/
486 /* Determine task dmap. */
487 dp
= &dmap
[(dev
>> MAJOR
) & BYTE
];
489 dev_mess
.m_type
= op
;
490 dev_mess
.DEVICE
= (dev
>> MINOR
) & BYTE
;
491 dev_mess
.IO_ENDPT
= proc_e
;
492 dev_mess
.COUNT
= flags
;
494 if (dp
->dmap_driver
== NONE
) {
495 printf("FS: gen_opcl: no driver for dev %x\n", dev
);
500 r
= (*dp
->dmap_io
)(dp
->dmap_driver
, &dev_mess
);
501 if (r
!= OK
) return(r
);
503 return(dev_mess
.REP_STATUS
);
506 /*===========================================================================*
508 *===========================================================================*/
509 PUBLIC
int tty_opcl(op
, dev
, proc_e
, flags
)
510 int op
; /* operation, DEV_OPEN or DEV_CLOSE */
511 dev_t dev
; /* device to open or close */
512 int proc_e
; /* process to open/close for */
513 int flags
; /* mode bits and flags */
515 /* This procedure is called from the dmap struct on tty open/close. */
518 register struct fproc
*rfp
;
520 /* Add O_NOCTTY to the flags if this process is not a session leader, or
521 * if it already has a controlling tty, or if it is someone elses
524 if (!fp
->fp_sesldr
|| fp
->fp_tty
!= 0) {
527 for (rfp
= &fproc
[0]; rfp
< &fproc
[NR_PROCS
]; rfp
++) {
528 if(rfp
->fp_pid
== PID_FREE
) continue;
529 if (rfp
->fp_tty
== dev
) flags
|= O_NOCTTY
;
533 r
= gen_opcl(op
, dev
, proc_e
, flags
);
535 /* Did this call make the tty the controlling tty? */
544 /*===========================================================================*
546 *===========================================================================*/
547 PUBLIC
int ctty_opcl(op
, dev
, proc_e
, flags
)
548 int op
; /* operation, DEV_OPEN or DEV_CLOSE */
549 dev_t dev
; /* device to open or close */
550 int proc_e
; /* process to open/close for */
551 int flags
; /* mode bits and flags */
553 /* This procedure is called from the dmap struct in table.c on opening/closing
554 * /dev/tty, the magic device that translates to the controlling tty.
557 return(fp
->fp_tty
== 0 ? ENXIO
: OK
);
561 /*===========================================================================*
563 *===========================================================================*/
564 PUBLIC
void pm_setsid(proc_e
)
567 /* Perform the FS side of the SETSID call, i.e. get rid of the controlling
568 * terminal of a process, and make the process a session leader.
570 register struct fproc
*rfp
;
573 /* Make the process a session leader with no controlling tty. */
574 okendpt(proc_e
, &slot
);
576 rfp
->fp_sesldr
= TRUE
;
581 /*===========================================================================*
583 *===========================================================================*/
584 PUBLIC
int do_ioctl()
586 /* Perform the ioctl(ls_fd, request, argx) system call (uses m2 fmt). */
590 register struct vnode
*vp
;
593 if ((f
= get_filp(m_in
.ls_fd
)) == NIL_FILP
) return(err_code
);
594 vp
= f
->filp_vno
; /* get vnode pointer */
595 if ((vp
->v_mode
& I_TYPE
) != I_CHAR_SPECIAL
&&
596 (vp
->v_mode
& I_TYPE
) != I_BLOCK_SPECIAL
) return(ENOTTY
);
597 suspend_reopen
= (f
->filp_state
!= FS_NORMAL
);
598 dev
= (dev_t
) vp
->v_sdev
;
600 return dev_io(VFS_DEV_IOCTL
, dev
, who_e
, m_in
.ADDRESS
, cvu64(0),
601 m_in
.REQUEST
, f
->filp_flags
, suspend_reopen
);
605 /*===========================================================================*
607 *===========================================================================*/
608 PUBLIC
int gen_io(task_nr
, mess_ptr
)
609 int task_nr
; /* which task to call */
610 message
*mess_ptr
; /* pointer to message for task */
612 /* All file system I/O ultimately comes down to I/O on major/minor device
613 * pairs. These lead to calls on the following routines via the dmap table.
618 if(task_nr
== SYSTEM
) printf("VFS: sending %d to SYSTEM\n", mess_ptr
->m_type
);
620 proc_e
= mess_ptr
->IO_ENDPT
;
621 r
= sendrec(task_nr
, mess_ptr
);
623 if (r
== EDEADSRCDST
|| r
== EDSTDIED
|| r
== ESRCDIED
) {
624 printf("fs: dead driver %d\n", task_nr
);
625 dmap_unmap_by_endpt(task_nr
);
629 printf("fs: ELOCKED talking to %d\n", task_nr
);
632 panic(__FILE__
,"call_task: can't send/receive", r
);
635 /* Did the process we did the sendrec() for get a result? */
636 if (mess_ptr
->REP_ENDPT
!= proc_e
) {
637 printf("fs: strange device reply from %d, type = %d, proc = %d "
638 "(not %d) (2) ignored\n", mess_ptr
->m_source
, mess_ptr
->m_type
,
639 proc_e
, mess_ptr
->REP_ENDPT
);
647 /*===========================================================================*
649 *===========================================================================*/
650 PUBLIC
int asyn_io(task_nr
, mess_ptr
)
651 int task_nr
; /* which task to call */
652 message
*mess_ptr
; /* pointer to message for task */
654 /* All file system I/O ultimately comes down to I/O on major/minor device
655 * pairs. These lead to calls on the following routines via the dmap table.
660 proc_e
= mess_ptr
->IO_ENDPT
;
662 r
= asynsend(task_nr
, mess_ptr
);
663 if (r
!= OK
) panic(__FILE__
, "asyn_io: asynsend failed", r
);
666 mess_ptr
->REP_STATUS
= SUSPEND
;
671 /*===========================================================================*
673 *===========================================================================*/
674 PUBLIC
int ctty_io(task_nr
, mess_ptr
)
675 int task_nr
; /* not used - for compatibility with dmap_t */
676 message
*mess_ptr
; /* pointer to message for task */
678 /* This routine is only called for one device, namely /dev/tty. Its job
679 * is to change the message to use the controlling terminal, instead of the
680 * major/minor pair for /dev/tty itself.
685 if (fp
->fp_tty
== 0) {
686 /* No controlling tty present anymore, return an I/O error. */
687 mess_ptr
->REP_STATUS
= EIO
;
689 /* Substitute the controlling terminal device. */
690 dp
= &dmap
[(fp
->fp_tty
>> MAJOR
) & BYTE
];
691 mess_ptr
->DEVICE
= (fp
->fp_tty
>> MINOR
) & BYTE
;
693 if (dp
->dmap_driver
== NONE
) {
694 printf("FS: ctty_io: no driver for dev\n");
698 if(isokendpt(dp
->dmap_driver
, &dummyproc
) != OK
) {
699 printf("FS: ctty_io: old driver %d\n", dp
->dmap_driver
);
703 (*dp
->dmap_io
)(dp
->dmap_driver
, mess_ptr
);
709 /*===========================================================================*
711 *===========================================================================*/
712 PUBLIC
int no_dev(op
, dev
, proc
, flags
)
713 int op
; /* operation, DEV_OPEN or DEV_CLOSE */
714 dev_t dev
; /* device to open or close */
715 int proc
; /* process to open/close for */
716 int flags
; /* mode bits and flags */
718 /* Called when opening a nonexistent device. */
722 /*===========================================================================*
724 *===========================================================================*/
725 PUBLIC
int no_dev_io(int proc
, message
*m
)
727 /* Called when doing i/o on a nonexistent device. */
728 printf("VFS: I/O on unmapped device number\n");
733 /*===========================================================================*
735 *===========================================================================*/
736 PUBLIC
int clone_opcl(op
, dev
, proc_e
, flags
)
737 int op
; /* operation, DEV_OPEN or DEV_CLOSE */
738 dev_t dev
; /* device to open or close */
739 int proc_e
; /* process to open/close for */
740 int flags
; /* mode bits and flags */
742 /* Some devices need special processing upon open. Such a device is "cloned",
743 * i.e. on a succesful open it is replaced by a new device with a new unique
744 * minor device number. This new device number identifies a new object (such
745 * as a new network connection) that has been allocated within a task.
751 /* Determine task dmap. */
752 dp
= &dmap
[(dev
>> MAJOR
) & BYTE
];
753 minor
= (dev
>> MINOR
) & BYTE
;
755 dev_mess
.m_type
= op
;
756 dev_mess
.DEVICE
= minor
;
757 dev_mess
.IO_ENDPT
= proc_e
;
758 dev_mess
.COUNT
= flags
;
761 if (dp
->dmap_driver
== NONE
) {
762 printf("VFS clone_opcl: no driver for dev %x\n", dev
);
766 if(isokendpt(dp
->dmap_driver
, &dummyproc
) != OK
) {
767 printf("VFS clone_opcl: bad driver endpoint for dev %x (%d)\n", dev
,
773 r
= (*dp
->dmap_io
)(dp
->dmap_driver
, &dev_mess
);
774 if (r
!= OK
) return(r
);
776 if (op
== DEV_OPEN
&& dev_mess
.REP_STATUS
>= 0) {
777 if (dev_mess
.REP_STATUS
!= minor
) {
780 struct node_details res
;
782 /* A new minor device number has been returned.
783 * Request the root FS to create a temporary device file to
787 /* Device number of the new device. */
788 dev
= (dev
& ~(BYTE
<< MINOR
)) | (dev_mess
.REP_STATUS
<< MINOR
);
791 r
= req_newnode(ROOT_FS_E
, fp
->fp_effuid
, fp
->fp_effgid
,
792 ALL_MODES
| I_CHAR_SPECIAL
, dev
, &res
);
794 (void) clone_opcl(DEV_CLOSE
, dev
, proc_e
, 0);
798 /* Drop old node and use the new values */
799 vp
= fp
->fp_filp
[m_in
.fd
]->filp_vno
;
802 if ((vp
= get_free_vnode()) == NIL_VNODE
)
803 vp
= fp
->fp_filp
[m_in
.fd
]->filp_vno
;
805 vp
->v_fs_e
= res
.fs_e
;
806 if ((vmp
= find_vmnt(vp
->v_fs_e
)) == NIL_VMNT
)
807 printf("VFS clone_opcl: no vmnt found\n");
810 vp
->v_dev
= vmp
->m_dev
;
811 vp
->v_fs_e
= res
.fs_e
;
812 vp
->v_inode_nr
= res
.inode_nr
;
813 vp
->v_mode
= res
.fmode
;
817 fp
->fp_filp
[m_in
.fd
]->filp_vno
= vp
;
819 dev_mess
.REP_STATUS
= OK
;
821 return(dev_mess
.REP_STATUS
);
825 /*===========================================================================*
827 *===========================================================================*/
828 PUBLIC
void dev_up(int maj
)
830 /* A new device driver has been mapped in. This function
831 * checks if any filesystems are mounted on it, and if so,
832 * dev_open()s them so the filesystem can be reused.
834 int r
, new_driver_e
, needs_reopen
, fd_nr
;
841 /* Open a device once for every filp that's opened on it,
842 * and once for every filesystem mounted from it.
844 new_driver_e
= dmap
[maj
].dmap_driver
;
846 for (vmp
= &vmnt
[0]; vmp
< &vmnt
[NR_MNTS
]; ++vmp
) {
848 if (vmp
->m_dev
== NO_DEV
) continue;
849 if ( ((vmp
->m_dev
>> MAJOR
) & BYTE
) != maj
) continue;
850 minor
= ((vmp
->m_dev
>> MINOR
) & BYTE
);
852 if ((r
= dev_open(vmp
->m_dev
, FS_PROC_NR
,
853 vmp
->m_flags
? R_BIT
: (R_BIT
|W_BIT
))) != OK
) {
854 printf("VFS: mounted dev %d/%d re-open failed: %d.\n",
858 /* Send new driver endpoint */
859 if (OK
!= req_newdriver(vmp
->m_fs_e
, vmp
->m_dev
, new_driver_e
))
860 printf("VFSdev_up: error sending new driver endpoint."
861 " FS_e: %d req_nr: %d\n", vmp
->m_fs_e
, REQ_NEW_DRIVER
);
864 /* Look for processes that are suspened in an OPEN call. Set SUSP_REOPEN
865 * to indicate that this process was suspended before the call to dev_up.
867 for (rfp
= &fproc
[0]; rfp
< &fproc
[NR_PROCS
]; rfp
++) {
868 if(rfp
->fp_pid
== PID_FREE
) continue;
869 if(rfp
->fp_blocked_on
!= FP_BLOCKED_ON_DOPEN
) continue;
871 printf("dev_up: found process in FP_BLOCKED_ON_DOPEN, fd %d\n",
873 fd_nr
= (rfp
->fp_fd
>> 8);
874 fp
= rfp
->fp_filp
[fd_nr
];
876 if (!vp
) panic(__FILE__
, "restart_reopen: no vp", NO_NUM
);
877 if ((vp
->v_mode
& I_TYPE
) != I_CHAR_SPECIAL
) continue;
878 if (((vp
->v_sdev
>> MAJOR
) & BYTE
) != maj
) continue;
880 rfp
->fp_flags
|= SUSP_REOPEN
;
884 for (fp
= filp
; fp
< &filp
[NR_FILPS
]; fp
++) {
888 if(fp
->filp_count
< 1 || !(vp
= fp
->filp_vno
)) continue;
889 if(((vp
->v_sdev
>> MAJOR
) & BYTE
) != maj
) continue;
890 if(!(vp
->v_mode
& (I_BLOCK_SPECIAL
|I_CHAR_SPECIAL
))) continue;
892 fp
->filp_state
= FS_NEEDS_REOPEN
;
902 /*===========================================================================*
904 *===========================================================================*/
905 PRIVATE
void restart_reopen(maj
)
908 int n
, r
, minor
, fd_nr
;
914 for (fp
= filp
; fp
< &filp
[NR_FILPS
]; fp
++) {
915 if (fp
->filp_count
< 1 || !(vp
= fp
->filp_vno
)) continue;
916 if (fp
->filp_state
!= FS_NEEDS_REOPEN
) continue;
917 if (((vp
->v_sdev
>> MAJOR
) & BYTE
) != maj
) continue;
918 if ((vp
->v_mode
& I_TYPE
) != I_CHAR_SPECIAL
) continue;
919 minor
= ((vp
->v_sdev
>> MINOR
) & BYTE
);
921 if (!(fp
->filp_flags
& O_REOPEN
)) {
922 /* File descriptor is to be closed when driver restarts. */
924 if (n
!= fp
->filp_count
) {
925 printf("VFS: warning: invalidate/count "
926 "discrepancy (%d, %d)\n", n
, fp
->filp_count
);
932 r
= dev_reopen(vp
->v_sdev
, fp
-filp
, vp
->v_mode
& (R_BIT
|W_BIT
));
935 /* Device could not be reopened. Invalidate all filps on that device.*/
937 if (n
!= fp
->filp_count
) {
938 printf("VFS: warning: invalidate/count "
939 "discrepancy (%d, %d)\n", n
, fp
->filp_count
);
942 printf("VFS: file on dev %d/%d re-open failed: %d; "
943 "invalidated %d fd's.\n", maj
, minor
, r
, n
);
946 /* Nothing more to re-open. Restart suspended processes */
947 driver_e
= dmap
[maj
].dmap_driver
;
949 for (rfp
= &fproc
[0]; rfp
< &fproc
[NR_PROCS
]; rfp
++) {
950 if(rfp
->fp_pid
== PID_FREE
) continue;
951 if(rfp
->fp_blocked_on
== FP_BLOCKED_ON_OTHER
&&
952 rfp
->fp_task
== driver_e
&& (rfp
->fp_flags
& SUSP_REOPEN
)) {
953 rfp
->fp_flags
&= ~SUSP_REOPEN
;
954 rfp
->fp_blocked_on
= FP_BLOCKED_ON_NONE
;
955 reply(rfp
->fp_endpoint
, ERESTART
);
959 /* Look for processes that are suspened in an OPEN call */
960 for (rfp
= &fproc
[0]; rfp
< &fproc
[NR_PROCS
]; rfp
++) {
961 if (rfp
->fp_pid
== PID_FREE
) continue;
962 if (rfp
->fp_blocked_on
== FP_BLOCKED_ON_DOPEN
||
963 !(rfp
->fp_flags
& SUSP_REOPEN
)) continue;
965 printf("restart_reopen: found process in FP_BLOCKED_ON_DOPEN, fd %d\n",
967 fd_nr
= (rfp
->fp_fd
>> 8);
968 fp
= rfp
->fp_filp
[fd_nr
];
971 /* Open failed, and automatic reopen was not requested */
972 rfp
->fp_blocked_on
= FP_BLOCKED_ON_NONE
;
973 FD_CLR(fd_nr
, &rfp
->fp_filp_inuse
);
974 reply(rfp
->fp_endpoint
, EIO
);
979 if (!vp
) panic(__FILE__
, "restart_reopen: no vp", NO_NUM
);
980 if ((vp
->v_mode
& I_TYPE
) != I_CHAR_SPECIAL
) continue;
981 if (((vp
->v_sdev
>> MAJOR
) & BYTE
) != maj
) continue;
983 rfp
->fp_blocked_on
= FP_BLOCKED_ON_NONE
;
984 reply(rfp
->fp_endpoint
, fd_nr
);
989 /*===========================================================================*
991 *===========================================================================*/
992 PUBLIC
void reopen_reply()
995 int filp_no
, status
, maj
;
1000 driver_e
= m_in
.m_source
;
1001 filp_no
= m_in
.REP_ENDPT
;
1002 status
= m_in
.REP_STATUS
;
1004 if (filp_no
< 0 || filp_no
>= NR_FILPS
) {
1005 printf("reopen_reply: bad filp number %d from driver %d\n", filp_no
,
1010 fp
= &filp
[filp_no
];
1011 if (fp
->filp_count
< 1) {
1012 printf("reopen_reply: filp number %d not inuse (from driver %d)\n",
1019 printf("reopen_reply: no vnode for filp number %d (from driver %d)\n",
1024 if (fp
->filp_state
!= FS_NEEDS_REOPEN
) {
1025 printf("reopen_reply: bad state %d for filp number %d"
1026 " (from driver %d)\n", fp
->filp_state
, filp_no
, driver_e
);
1030 if ((vp
->v_mode
& I_TYPE
) != I_CHAR_SPECIAL
) {
1031 printf("reopen_reply: bad mode 0%o for filp number %d"
1032 " (from driver %d)\n", vp
->v_mode
, filp_no
, driver_e
);
1036 maj
= ((vp
->v_sdev
>> MAJOR
) & BYTE
);
1038 if (dp
->dmap_driver
!= driver_e
) {
1039 printf("reopen_reply: bad major %d for filp number %d "
1040 "(from driver %d, current driver is %d)\n", maj
, filp_no
,
1041 driver_e
, dp
->dmap_driver
);
1046 fp
->filp_state
= FS_NORMAL
;
1048 printf("reopen_reply: should handle error status\n");
1052 restart_reopen(maj
);
1057 PRIVATE asynmsg_t msgtable
[ASYN_NR
];
1058 PRIVATE
int first_slot
= 0, next_slot
= 0;
1060 PUBLIC
int asynsend(dst
, mp
)
1064 int r
, src_ind
, dst_ind
;
1067 /* Update first_slot */
1068 for (; first_slot
< next_slot
; first_slot
++)
1070 flags
= msgtable
[first_slot
].flags
;
1071 if ((flags
& (AMF_VALID
|AMF_DONE
)) == (AMF_VALID
|AMF_DONE
))
1073 if (msgtable
[first_slot
].result
!= OK
)
1076 "asynsend: found completed entry %d with error %d\n",
1078 msgtable
[first_slot
].result
);
1082 if (flags
!= AMF_EMPTY
)
1086 if (first_slot
>= next_slot
)
1088 /* Reset first_slot and next_slot */
1089 next_slot
= first_slot
= 0;
1092 if (next_slot
>= ASYN_NR
)
1094 /* Tell the kernel to stop processing */
1097 panic(__FILE__
, "asynsend: senda failed", r
);
1100 for (src_ind
= first_slot
; src_ind
<next_slot
; src_ind
++)
1102 flags
= msgtable
[src_ind
].flags
;
1103 if ((flags
& (AMF_VALID
|AMF_DONE
)) ==
1104 (AMF_VALID
|AMF_DONE
))
1106 if (msgtable
[src_ind
].result
!= OK
)
1109 "asynsend: found completed entry %d with error %d\n",
1111 msgtable
[src_ind
].result
);
1115 if (flags
== AMF_EMPTY
)
1118 printf("asynsend: copying entry %d to %d\n",
1121 if (src_ind
!= dst_ind
)
1122 msgtable
[dst_ind
]= msgtable
[src_ind
];
1127 if (next_slot
>= ASYN_NR
)
1128 panic(__FILE__
, "asynsend: msgtable full", NO_NUM
);
1131 msgtable
[next_slot
].dst
= dst
;
1132 msgtable
[next_slot
].msg
= *mp
;
1133 msgtable
[next_slot
].flags
= AMF_VALID
; /* Has to be last. The kernel
1134 * scans this table while we
1139 /* Tell the kernel to rescan the table */
1140 return senda(msgtable
+first_slot
, next_slot
-first_slot
);