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, safe
;
349 pos_high
= ex64hi(pos
);
351 /* Determine task dmap. */
352 dp
= &dmap
[(dev
>> MAJOR
) & BYTE
];
354 /* See if driver is roughly valid. */
355 if (dp
->dmap_driver
== NONE
) {
356 printf("FS: dev_io: no driver for dev %x\n", dev
);
360 if (suspend_reopen
) {
362 fp
->fp_grant
= GRANT_INVALID
;
363 fp
->fp_ioproc
= NONE
;
364 wait_for(dp
->dmap_driver
);
365 fp
->fp_flags
|= SUSP_REOPEN
;
369 if(isokendpt(dp
->dmap_driver
, &dummyproc
) != OK
) {
370 printf("FS: dev_io: old driver for dev %x (%d)\n",dev
,dp
->dmap_driver
);
374 /* By default, these are right. */
375 dev_mess
.IO_ENDPT
= proc_e
;
376 dev_mess
.ADDRESS
= buf
;
378 /* Convert DEV_* to DEV_*_S variants. */
380 safe
= safe_io_conversion(dp
->dmap_driver
, &gid
, &op
, gids
, NR_IOREQS
,
381 (endpoint_t
*) &dev_mess
.IO_ENDPT
, &buf_used
,
382 &vec_grants
, bytes
, &pos_lo
);
385 panic(__FILE__
,"dev_io: safe_io_conversion changed buffer", NO_NUM
);
387 /* If the safe conversion was done, set the ADDRESS to
390 if(safe
) dev_mess
.IO_GRANT
= (char *) gid
;
392 /* Set up the rest of the message passed to task. */
393 dev_mess
.m_type
= op
;
394 dev_mess
.DEVICE
= (dev
>> MINOR
) & BYTE
;
395 dev_mess
.POSITION
= pos_lo
;
396 dev_mess
.COUNT
= bytes
;
397 dev_mess
.HIGHPOS
= pos_high
;
399 /* This will be used if the i/o is suspended. */
400 ioproc
= dev_mess
.IO_ENDPT
;
403 (*dp
->dmap_io
)(dp
->dmap_driver
, &dev_mess
);
405 if(dp
->dmap_driver
== NONE
) {
406 /* Driver has vanished. */
407 printf("Driver gone?\n");
408 if(safe
) safe_io_cleanup(gid
, gids
, vec_grants
);
412 /* Task has completed. See if call completed. */
413 if (dev_mess
.REP_STATUS
== SUSPEND
) {
414 if(vec_grants
> 0) panic(__FILE__
,"SUSPEND on vectored i/o", NO_NUM
);
416 /* fp is uninitialized at init time. */
417 if(!fp
) panic(__FILE__
,"SUSPEND on NULL fp", NO_NUM
);
419 if ((flags
& O_NONBLOCK
) && !dp
->dmap_async_driver
) {
420 /* Not supposed to block. */
421 dev_mess
.m_type
= CANCEL
;
422 dev_mess
.IO_ENDPT
= ioproc
;
423 dev_mess
.IO_GRANT
= (char *) gid
;
425 /* This R_BIT/W_BIT check taken from suspend()/unpause()
426 * logic. Mode is expected in the COUNT field.
429 if (call_nr
== READ
) dev_mess
.COUNT
= R_BIT
;
430 else if (call_nr
== WRITE
) dev_mess
.COUNT
= W_BIT
;
431 dev_mess
.DEVICE
= (dev
>> MINOR
) & BYTE
;
432 (*dp
->dmap_io
)(dp
->dmap_driver
, &dev_mess
);
433 if (dev_mess
.REP_STATUS
== EINTR
) dev_mess
.REP_STATUS
= EAGAIN
;
435 /* select() will do suspending itself. */
436 if(op
!= DEV_SELECT
) {
438 wait_for(dp
->dmap_driver
);
440 assert(!GRANT_VALID(fp
->fp_grant
));
441 fp
->fp_grant
= gid
; /* revoke this when unsuspended. */
442 fp
->fp_ioproc
= ioproc
;
444 if (flags
& O_NONBLOCK
) {
445 /* Not supposed to block, send cancel message */
446 dev_mess
.m_type
= CANCEL
;
447 dev_mess
.IO_ENDPT
= ioproc
;
448 dev_mess
.IO_GRANT
= (char *) gid
;
450 /* This R_BIT/W_BIT check taken from suspend()/unpause()
451 * logic. Mode is expected in the COUNT field.
454 if(call_nr
== READ
) dev_mess
.COUNT
= R_BIT
;
455 else if(call_nr
== WRITE
) dev_mess
.COUNT
= W_BIT
;
456 dev_mess
.DEVICE
= (dev
>> MINOR
) & BYTE
;
457 (*dp
->dmap_io
)(dp
->dmap_driver
, &dev_mess
);
459 /* Should do something about EINTR -> EAGAIN mapping */
465 /* No suspend, or cancelled suspend, so I/O is over and can be cleaned up. */
466 if(safe
) safe_io_cleanup(gid
, gids
, vec_grants
);
468 return(dev_mess
.REP_STATUS
);
471 /*===========================================================================*
473 *===========================================================================*/
474 PUBLIC
int gen_opcl(op
, dev
, proc_e
, flags
)
475 int op
; /* operation, DEV_OPEN or DEV_CLOSE */
476 dev_t dev
; /* device to open or close */
477 int proc_e
; /* process to open/close for */
478 int flags
; /* mode bits and flags */
480 /* Called from the dmap struct in table.c on opens & closes of special files.*/
485 /* Determine task dmap. */
486 dp
= &dmap
[(dev
>> MAJOR
) & BYTE
];
488 dev_mess
.m_type
= op
;
489 dev_mess
.DEVICE
= (dev
>> MINOR
) & BYTE
;
490 dev_mess
.IO_ENDPT
= proc_e
;
491 dev_mess
.COUNT
= flags
;
493 if (dp
->dmap_driver
== NONE
) {
494 printf("FS: gen_opcl: no driver for dev %x\n", dev
);
499 r
= (*dp
->dmap_io
)(dp
->dmap_driver
, &dev_mess
);
500 if (r
!= OK
) return(r
);
502 return(dev_mess
.REP_STATUS
);
505 /*===========================================================================*
507 *===========================================================================*/
508 PUBLIC
int tty_opcl(op
, dev
, proc_e
, flags
)
509 int op
; /* operation, DEV_OPEN or DEV_CLOSE */
510 dev_t dev
; /* device to open or close */
511 int proc_e
; /* process to open/close for */
512 int flags
; /* mode bits and flags */
514 /* This procedure is called from the dmap struct on tty open/close. */
517 register struct fproc
*rfp
;
519 /* Add O_NOCTTY to the flags if this process is not a session leader, or
520 * if it already has a controlling tty, or if it is someone elses
523 if (!fp
->fp_sesldr
|| fp
->fp_tty
!= 0) {
526 for (rfp
= &fproc
[0]; rfp
< &fproc
[NR_PROCS
]; rfp
++) {
527 if(rfp
->fp_pid
== PID_FREE
) continue;
528 if (rfp
->fp_tty
== dev
) flags
|= O_NOCTTY
;
532 r
= gen_opcl(op
, dev
, proc_e
, flags
);
534 /* Did this call make the tty the controlling tty? */
543 /*===========================================================================*
545 *===========================================================================*/
546 PUBLIC
int ctty_opcl(op
, dev
, proc_e
, flags
)
547 int op
; /* operation, DEV_OPEN or DEV_CLOSE */
548 dev_t dev
; /* device to open or close */
549 int proc_e
; /* process to open/close for */
550 int flags
; /* mode bits and flags */
552 /* This procedure is called from the dmap struct in table.c on opening/closing
553 * /dev/tty, the magic device that translates to the controlling tty.
556 return(fp
->fp_tty
== 0 ? ENXIO
: OK
);
560 /*===========================================================================*
562 *===========================================================================*/
563 PUBLIC
void pm_setsid(proc_e
)
566 /* Perform the FS side of the SETSID call, i.e. get rid of the controlling
567 * terminal of a process, and make the process a session leader.
569 register struct fproc
*rfp
;
572 /* Make the process a session leader with no controlling tty. */
573 okendpt(proc_e
, &slot
);
575 rfp
->fp_sesldr
= TRUE
;
580 /*===========================================================================*
582 *===========================================================================*/
583 PUBLIC
int do_ioctl()
585 /* Perform the ioctl(ls_fd, request, argx) system call (uses m2 fmt). */
589 register struct vnode
*vp
;
592 if ((f
= get_filp(m_in
.ls_fd
)) == NIL_FILP
) return(err_code
);
593 vp
= f
->filp_vno
; /* get vnode pointer */
594 if ((vp
->v_mode
& I_TYPE
) != I_CHAR_SPECIAL
&&
595 (vp
->v_mode
& I_TYPE
) != I_BLOCK_SPECIAL
) return(ENOTTY
);
596 suspend_reopen
= (f
->filp_state
!= FS_NORMAL
);
597 dev
= (dev_t
) vp
->v_sdev
;
599 return dev_io(VFS_DEV_IOCTL
, dev
, who_e
, m_in
.ADDRESS
, cvu64(0),
600 m_in
.REQUEST
, f
->filp_flags
, suspend_reopen
);
604 /*===========================================================================*
606 *===========================================================================*/
607 PUBLIC
int gen_io(task_nr
, mess_ptr
)
608 int task_nr
; /* which task to call */
609 message
*mess_ptr
; /* pointer to message for task */
611 /* All file system I/O ultimately comes down to I/O on major/minor device
612 * pairs. These lead to calls on the following routines via the dmap table.
617 if(task_nr
== SYSTEM
) printf("VFS: sending %d to SYSTEM\n", mess_ptr
->m_type
);
619 proc_e
= mess_ptr
->IO_ENDPT
;
620 r
= sendrec(task_nr
, mess_ptr
);
622 if (r
== EDEADSRCDST
|| r
== EDSTDIED
|| r
== ESRCDIED
) {
623 printf("fs: dead driver %d\n", task_nr
);
624 dmap_unmap_by_endpt(task_nr
);
628 printf("fs: ELOCKED talking to %d\n", task_nr
);
631 panic(__FILE__
,"call_task: can't send/receive", r
);
634 /* Did the process we did the sendrec() for get a result? */
635 if (mess_ptr
->REP_ENDPT
!= proc_e
) {
636 printf("fs: strange device reply from %d, type = %d, proc = %d "
637 "(not %d) (2) ignored\n", mess_ptr
->m_source
, mess_ptr
->m_type
,
638 proc_e
, mess_ptr
->REP_ENDPT
);
646 /*===========================================================================*
648 *===========================================================================*/
649 PUBLIC
int asyn_io(task_nr
, mess_ptr
)
650 int task_nr
; /* which task to call */
651 message
*mess_ptr
; /* pointer to message for task */
653 /* All file system I/O ultimately comes down to I/O on major/minor device
654 * pairs. These lead to calls on the following routines via the dmap table.
659 r
= asynsend(task_nr
, mess_ptr
);
660 if (r
!= OK
) panic(__FILE__
, "asyn_io: asynsend failed", r
);
663 mess_ptr
->REP_STATUS
= SUSPEND
;
668 /*===========================================================================*
670 *===========================================================================*/
671 PUBLIC
int ctty_io(task_nr
, mess_ptr
)
672 int task_nr
; /* not used - for compatibility with dmap_t */
673 message
*mess_ptr
; /* pointer to message for task */
675 /* This routine is only called for one device, namely /dev/tty. Its job
676 * is to change the message to use the controlling terminal, instead of the
677 * major/minor pair for /dev/tty itself.
682 if (fp
->fp_tty
== 0) {
683 /* No controlling tty present anymore, return an I/O error. */
684 mess_ptr
->REP_STATUS
= EIO
;
686 /* Substitute the controlling terminal device. */
687 dp
= &dmap
[(fp
->fp_tty
>> MAJOR
) & BYTE
];
688 mess_ptr
->DEVICE
= (fp
->fp_tty
>> MINOR
) & BYTE
;
690 if (dp
->dmap_driver
== NONE
) {
691 printf("FS: ctty_io: no driver for dev\n");
695 if(isokendpt(dp
->dmap_driver
, &dummyproc
) != OK
) {
696 printf("FS: ctty_io: old driver %d\n", dp
->dmap_driver
);
700 (*dp
->dmap_io
)(dp
->dmap_driver
, mess_ptr
);
706 /*===========================================================================*
708 *===========================================================================*/
709 PUBLIC
int no_dev(op
, dev
, proc
, flags
)
710 int op
; /* operation, DEV_OPEN or DEV_CLOSE */
711 dev_t dev
; /* device to open or close */
712 int proc
; /* process to open/close for */
713 int flags
; /* mode bits and flags */
715 /* Called when opening a nonexistent device. */
719 /*===========================================================================*
721 *===========================================================================*/
722 PUBLIC
int no_dev_io(int proc
, message
*m
)
724 /* Called when doing i/o on a nonexistent device. */
725 printf("VFS: I/O on unmapped device number\n");
730 /*===========================================================================*
732 *===========================================================================*/
733 PUBLIC
int clone_opcl(op
, dev
, proc_e
, flags
)
734 int op
; /* operation, DEV_OPEN or DEV_CLOSE */
735 dev_t dev
; /* device to open or close */
736 int proc_e
; /* process to open/close for */
737 int flags
; /* mode bits and flags */
739 /* Some devices need special processing upon open. Such a device is "cloned",
740 * i.e. on a succesful open it is replaced by a new device with a new unique
741 * minor device number. This new device number identifies a new object (such
742 * as a new network connection) that has been allocated within a task.
748 /* Determine task dmap. */
749 dp
= &dmap
[(dev
>> MAJOR
) & BYTE
];
750 minor
= (dev
>> MINOR
) & BYTE
;
752 dev_mess
.m_type
= op
;
753 dev_mess
.DEVICE
= minor
;
754 dev_mess
.IO_ENDPT
= proc_e
;
755 dev_mess
.COUNT
= flags
;
758 if (dp
->dmap_driver
== NONE
) {
759 printf("VFS clone_opcl: no driver for dev %x\n", dev
);
763 if(isokendpt(dp
->dmap_driver
, &dummyproc
) != OK
) {
764 printf("VFS clone_opcl: bad driver endpoint for dev %x (%d)\n", dev
,
770 r
= (*dp
->dmap_io
)(dp
->dmap_driver
, &dev_mess
);
771 if (r
!= OK
) return(r
);
773 if (op
== DEV_OPEN
&& dev_mess
.REP_STATUS
>= 0) {
774 if (dev_mess
.REP_STATUS
!= minor
) {
777 struct node_details res
;
779 /* A new minor device number has been returned.
780 * Request the root FS to create a temporary device file to
784 /* Device number of the new device. */
785 dev
= (dev
& ~(BYTE
<< MINOR
)) | (dev_mess
.REP_STATUS
<< MINOR
);
788 r
= req_newnode(ROOT_FS_E
, fp
->fp_effuid
, fp
->fp_effgid
,
789 ALL_MODES
| I_CHAR_SPECIAL
, dev
, &res
);
791 (void) clone_opcl(DEV_CLOSE
, dev
, proc_e
, 0);
795 /* Drop old node and use the new values */
796 vp
= fp
->fp_filp
[m_in
.fd
]->filp_vno
;
799 if ((vp
= get_free_vnode()) == NIL_VNODE
)
800 vp
= fp
->fp_filp
[m_in
.fd
]->filp_vno
;
802 vp
->v_fs_e
= res
.fs_e
;
803 if ((vmp
= find_vmnt(vp
->v_fs_e
)) == NIL_VMNT
)
804 printf("VFS clone_opcl: no vmnt found\n");
807 vp
->v_dev
= vmp
->m_dev
;
808 vp
->v_fs_e
= res
.fs_e
;
809 vp
->v_inode_nr
= res
.inode_nr
;
810 vp
->v_mode
= res
.fmode
;
814 fp
->fp_filp
[m_in
.fd
]->filp_vno
= vp
;
816 dev_mess
.REP_STATUS
= OK
;
818 return(dev_mess
.REP_STATUS
);
822 /*===========================================================================*
824 *===========================================================================*/
825 PUBLIC
void dev_up(int maj
)
827 /* A new device driver has been mapped in. This function
828 * checks if any filesystems are mounted on it, and if so,
829 * dev_open()s them so the filesystem can be reused.
831 int r
, new_driver_e
, needs_reopen
, fd_nr
;
838 /* Open a device once for every filp that's opened on it,
839 * and once for every filesystem mounted from it.
841 new_driver_e
= dmap
[maj
].dmap_driver
;
843 for (vmp
= &vmnt
[0]; vmp
< &vmnt
[NR_MNTS
]; ++vmp
) {
845 if (vmp
->m_dev
== NO_DEV
) continue;
846 if ( ((vmp
->m_dev
>> MAJOR
) & BYTE
) != maj
) continue;
847 minor
= ((vmp
->m_dev
>> MINOR
) & BYTE
);
849 if ((r
= dev_open(vmp
->m_dev
, FS_PROC_NR
,
850 vmp
->m_flags
? R_BIT
: (R_BIT
|W_BIT
))) != OK
) {
851 printf("VFS: mounted dev %d/%d re-open failed: %d.\n",
855 /* Send new driver endpoint */
856 if (OK
!= req_newdriver(vmp
->m_fs_e
, vmp
->m_dev
, new_driver_e
))
857 printf("VFSdev_up: error sending new driver endpoint."
858 " FS_e: %d req_nr: %d\n", vmp
->m_fs_e
, REQ_NEW_DRIVER
);
861 /* Look for processes that are suspened in an OPEN call. Set SUSP_REOPEN
862 * to indicate that this process was suspended before the call to dev_up.
864 for (rfp
= &fproc
[0]; rfp
< &fproc
[NR_PROCS
]; rfp
++) {
865 if(rfp
->fp_pid
== PID_FREE
) continue;
866 if(rfp
->fp_blocked_on
!= FP_BLOCKED_ON_DOPEN
) continue;
868 printf("dev_up: found process in FP_BLOCKED_ON_DOPEN, fd %d\n",
870 fd_nr
= (rfp
->fp_fd
>> 8);
871 fp
= rfp
->fp_filp
[fd_nr
];
873 if (!vp
) panic(__FILE__
, "restart_reopen: no vp", NO_NUM
);
874 if ((vp
->v_mode
& I_TYPE
) != I_CHAR_SPECIAL
) continue;
875 if (((vp
->v_sdev
>> MAJOR
) & BYTE
) != maj
) continue;
877 rfp
->fp_flags
|= SUSP_REOPEN
;
881 for (fp
= filp
; fp
< &filp
[NR_FILPS
]; fp
++) {
885 if(fp
->filp_count
< 1 || !(vp
= fp
->filp_vno
)) continue;
886 if(((vp
->v_sdev
>> MAJOR
) & BYTE
) != maj
) continue;
887 if(!(vp
->v_mode
& (I_BLOCK_SPECIAL
|I_CHAR_SPECIAL
))) continue;
889 fp
->filp_state
= FS_NEEDS_REOPEN
;
899 /*===========================================================================*
901 *===========================================================================*/
902 PRIVATE
void restart_reopen(maj
)
905 int n
, r
, minor
, fd_nr
;
911 for (fp
= filp
; fp
< &filp
[NR_FILPS
]; fp
++) {
912 if (fp
->filp_count
< 1 || !(vp
= fp
->filp_vno
)) continue;
913 if (fp
->filp_state
!= FS_NEEDS_REOPEN
) continue;
914 if (((vp
->v_sdev
>> MAJOR
) & BYTE
) != maj
) continue;
915 if ((vp
->v_mode
& I_TYPE
) != I_CHAR_SPECIAL
) continue;
916 minor
= ((vp
->v_sdev
>> MINOR
) & BYTE
);
918 if (!(fp
->filp_flags
& O_REOPEN
)) {
919 /* File descriptor is to be closed when driver restarts. */
921 if (n
!= fp
->filp_count
) {
922 printf("VFS: warning: invalidate/count "
923 "discrepancy (%d, %d)\n", n
, fp
->filp_count
);
929 r
= dev_reopen(vp
->v_sdev
, fp
-filp
, vp
->v_mode
& (R_BIT
|W_BIT
));
932 /* Device could not be reopened. Invalidate all filps on that device.*/
934 if (n
!= fp
->filp_count
) {
935 printf("VFS: warning: invalidate/count "
936 "discrepancy (%d, %d)\n", n
, fp
->filp_count
);
939 printf("VFS: file on dev %d/%d re-open failed: %d; "
940 "invalidated %d fd's.\n", maj
, minor
, r
, n
);
943 /* Nothing more to re-open. Restart suspended processes */
944 driver_e
= dmap
[maj
].dmap_driver
;
946 for (rfp
= &fproc
[0]; rfp
< &fproc
[NR_PROCS
]; rfp
++) {
947 if(rfp
->fp_pid
== PID_FREE
) continue;
948 if(rfp
->fp_blocked_on
== FP_BLOCKED_ON_OTHER
&&
949 rfp
->fp_task
== driver_e
&& (rfp
->fp_flags
& SUSP_REOPEN
)) {
950 rfp
->fp_flags
&= ~SUSP_REOPEN
;
951 rfp
->fp_blocked_on
= FP_BLOCKED_ON_NONE
;
952 reply(rfp
->fp_endpoint
, ERESTART
);
956 /* Look for processes that are suspened in an OPEN call */
957 for (rfp
= &fproc
[0]; rfp
< &fproc
[NR_PROCS
]; rfp
++) {
958 if (rfp
->fp_pid
== PID_FREE
) continue;
959 if (rfp
->fp_blocked_on
== FP_BLOCKED_ON_DOPEN
||
960 !(rfp
->fp_flags
& SUSP_REOPEN
)) continue;
962 printf("restart_reopen: found process in FP_BLOCKED_ON_DOPEN, fd %d\n",
964 fd_nr
= (rfp
->fp_fd
>> 8);
965 fp
= rfp
->fp_filp
[fd_nr
];
968 /* Open failed, and automatic reopen was not requested */
969 rfp
->fp_blocked_on
= FP_BLOCKED_ON_NONE
;
970 FD_CLR(fd_nr
, &rfp
->fp_filp_inuse
);
971 reply(rfp
->fp_endpoint
, EIO
);
976 if (!vp
) panic(__FILE__
, "restart_reopen: no vp", NO_NUM
);
977 if ((vp
->v_mode
& I_TYPE
) != I_CHAR_SPECIAL
) continue;
978 if (((vp
->v_sdev
>> MAJOR
) & BYTE
) != maj
) continue;
980 rfp
->fp_blocked_on
= FP_BLOCKED_ON_NONE
;
981 reply(rfp
->fp_endpoint
, fd_nr
);
986 /*===========================================================================*
988 *===========================================================================*/
989 PUBLIC
void reopen_reply()
992 int filp_no
, status
, maj
;
997 driver_e
= m_in
.m_source
;
998 filp_no
= m_in
.REP_ENDPT
;
999 status
= m_in
.REP_STATUS
;
1001 if (filp_no
< 0 || filp_no
>= NR_FILPS
) {
1002 printf("reopen_reply: bad filp number %d from driver %d\n", filp_no
,
1007 fp
= &filp
[filp_no
];
1008 if (fp
->filp_count
< 1) {
1009 printf("reopen_reply: filp number %d not inuse (from driver %d)\n",
1016 printf("reopen_reply: no vnode for filp number %d (from driver %d)\n",
1021 if (fp
->filp_state
!= FS_NEEDS_REOPEN
) {
1022 printf("reopen_reply: bad state %d for filp number %d"
1023 " (from driver %d)\n", fp
->filp_state
, filp_no
, driver_e
);
1027 if ((vp
->v_mode
& I_TYPE
) != I_CHAR_SPECIAL
) {
1028 printf("reopen_reply: bad mode 0%o for filp number %d"
1029 " (from driver %d)\n", vp
->v_mode
, filp_no
, driver_e
);
1033 maj
= ((vp
->v_sdev
>> MAJOR
) & BYTE
);
1035 if (dp
->dmap_driver
!= driver_e
) {
1036 printf("reopen_reply: bad major %d for filp number %d "
1037 "(from driver %d, current driver is %d)\n", maj
, filp_no
,
1038 driver_e
, dp
->dmap_driver
);
1043 fp
->filp_state
= FS_NORMAL
;
1045 printf("reopen_reply: should handle error status\n");
1049 restart_reopen(maj
);
1054 PRIVATE asynmsg_t msgtable
[ASYN_NR
];
1055 PRIVATE
int first_slot
= 0, next_slot
= 0;
1057 PUBLIC
int asynsend(dst
, mp
)
1061 int r
, src_ind
, dst_ind
;
1064 /* Update first_slot */
1065 for (; first_slot
< next_slot
; first_slot
++)
1067 flags
= msgtable
[first_slot
].flags
;
1068 if ((flags
& (AMF_VALID
|AMF_DONE
)) == (AMF_VALID
|AMF_DONE
))
1070 if (msgtable
[first_slot
].result
!= OK
)
1073 "asynsend: found completed entry %d with error %d\n",
1075 msgtable
[first_slot
].result
);
1079 if (flags
!= AMF_EMPTY
)
1083 if (first_slot
>= next_slot
)
1085 /* Reset first_slot and next_slot */
1086 next_slot
= first_slot
= 0;
1089 if (next_slot
>= ASYN_NR
)
1091 /* Tell the kernel to stop processing */
1094 panic(__FILE__
, "asynsend: senda failed", r
);
1097 for (src_ind
= first_slot
; src_ind
<next_slot
; src_ind
++)
1099 flags
= msgtable
[src_ind
].flags
;
1100 if ((flags
& (AMF_VALID
|AMF_DONE
)) ==
1101 (AMF_VALID
|AMF_DONE
))
1103 if (msgtable
[src_ind
].result
!= OK
)
1106 "asynsend: found completed entry %d with error %d\n",
1108 msgtable
[src_ind
].result
);
1112 if (flags
== AMF_EMPTY
)
1115 printf("asynsend: copying entry %d to %d\n",
1118 if (src_ind
!= dst_ind
)
1119 msgtable
[dst_ind
]= msgtable
[src_ind
];
1124 if (next_slot
>= ASYN_NR
)
1125 panic(__FILE__
, "asynsend: msgtable full", NO_NUM
);
1128 msgtable
[next_slot
].dst
= dst
;
1129 msgtable
[next_slot
].msg
= *mp
;
1130 msgtable
[next_slot
].flags
= AMF_VALID
; /* Has to be last. The kernel
1131 * scans this table while we
1136 /* Tell the kernel to rescan the table */
1137 return senda(msgtable
+first_slot
, next_slot
-first_slot
);