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: open a character device
6 * dev_reopen: reopen a character device after a driver crash
7 * dev_close: close a character device
8 * bdev_open: open a block device
9 * bdev_close: close a block device
10 * dev_io: FS does a read or write on a device
11 * dev_status: FS processes callback request alert
12 * gen_opcl: generic call to a task to perform an open/close
13 * gen_io: generic call to a task to perform an I/O operation
14 * no_dev: open/close processing for devices that don't exist
15 * no_dev_io: i/o processing for devices that don't exist
16 * tty_opcl: perform tty-specific processing for open/close
17 * ctty_opcl: perform controlling-tty-specific processing for open/close
18 * ctty_io: perform controlling-tty-specific processing for I/O
19 * pm_setsid: perform VFS's side of setsid system call
20 * do_ioctl: perform the IOCTL system call
28 #include <minix/callnr.h>
29 #include <minix/com.h>
30 #include <minix/endpoint.h>
31 #include <minix/ioctl.h>
32 #include <minix/u64.h>
35 #include "scratchpad.h"
37 #include <minix/vfsif.h>
42 static void restart_reopen(int major
);
43 static int safe_io_conversion(endpoint_t
, cp_grant_id_t
*, int *,
44 endpoint_t
*, void **, size_t, u32_t
*);
49 /*===========================================================================*
51 *===========================================================================*/
53 dev_t dev
, /* device to open */
54 endpoint_t proc_e
, /* process to open for */
55 int flags
/* mode bits and flags */
58 /* Open a character device. */
61 /* Determine the major device number so as to call the device class specific
62 * open/close routine. (This is the only routine that must check the
63 * device number for being in range. All others can trust this check.)
66 if (major
< 0 || major
>= NR_DEVICES
) major
= 0;
67 if (dmap
[major
].dmap_driver
== NONE
) return(ENXIO
);
68 r
= (*dmap
[major
].dmap_opcl
)(DEV_OPEN
, dev
, proc_e
, flags
);
73 /*===========================================================================*
75 *===========================================================================*/
77 dev_t dev
, /* device to open */
78 int filp_no
, /* filp to reopen for */
79 int flags
/* mode bits and flags */
82 /* Reopen a character device after a failing device driver. */
87 /* Determine the major device number and call the device class specific
88 * open/close routine. (This is the only routine that must check the device
89 * number for being in range. All others can trust this check.)
93 if (major
< 0 || major
>= NR_DEVICES
) major
= 0;
95 if (dp
->dmap_driver
== NONE
) return(ENXIO
);
96 r
= (*dp
->dmap_opcl
)(DEV_REOPEN
, dev
, filp_no
, flags
);
97 if (r
== SUSPEND
) r
= OK
;
102 /*===========================================================================*
104 *===========================================================================*/
106 dev_t dev
, /* device to close */
110 /* Close a character device. */
113 /* See if driver is roughly valid. */
115 if (major
< 0 || major
>= NR_DEVICES
) return(ENXIO
);
116 if (dmap
[major
].dmap_driver
== NONE
) return(ENXIO
);
117 r
= (*dmap
[major
].dmap_opcl
)(DEV_CLOSE
, dev
, filp_no
, 0);
122 /*===========================================================================*
124 *===========================================================================*/
125 int bdev_open(dev_t dev
, int access
)
127 /* Open a block device. */
131 if (major
< 0 || major
>= NR_DEVICES
) return(ENXIO
);
132 if (dmap
[major
].dmap_driver
== NONE
) return(ENXIO
);
134 return (*dmap
[major
].dmap_opcl
)(BDEV_OPEN
, dev
, 0, access
);
138 /*===========================================================================*
140 *===========================================================================*/
141 int bdev_close(dev_t dev
)
143 /* Close a block device. */
147 if (major
< 0 || major
>= NR_DEVICES
) return(ENXIO
);
148 if (dmap
[major
].dmap_driver
== NONE
) return(ENXIO
);
150 return (*dmap
[major
].dmap_opcl
)(BDEV_CLOSE
, dev
, 0, 0);
154 /*===========================================================================*
156 *===========================================================================*/
157 static int bdev_ioctl(dev_t dev
, endpoint_t proc_e
, int req
, void *buf
)
159 /* Perform an I/O control operation on a block device. */
164 int op
, major_dev
, minor_dev
;
166 major_dev
= major(dev
);
167 minor_dev
= minor(dev
);
169 /* Determine task dmap. */
170 dp
= &dmap
[major_dev
];
171 if (dp
->dmap_driver
== NONE
) {
172 printf("VFS: dev_io: no driver for major %d\n", major_dev
);
176 /* Set up a grant if necessary. */
178 (void) safe_io_conversion(dp
->dmap_driver
, &gid
, &op
, &proc_e
, &buf
, req
,
181 /* Set up the message passed to the task. */
182 memset(&dev_mess
, 0, sizeof(dev_mess
));
184 dev_mess
.m_type
= BDEV_IOCTL
;
185 dev_mess
.BDEV_MINOR
= minor_dev
;
186 dev_mess
.BDEV_REQUEST
= req
;
187 dev_mess
.BDEV_GRANT
= gid
;
188 dev_mess
.BDEV_ID
= 0;
191 (*dp
->dmap_io
)(dp
->dmap_driver
, &dev_mess
);
194 if (GRANT_VALID(gid
)) cpf_revoke(gid
);
196 if (dp
->dmap_driver
== NONE
) {
197 printf("VFS: block driver gone!?\n");
201 /* Return the result. */
202 return(dev_mess
.BDEV_STATUS
);
206 /*===========================================================================*
207 * find_suspended_ep *
208 *===========================================================================*/
209 endpoint_t
find_suspended_ep(endpoint_t driver
, cp_grant_id_t g
)
211 /* A process is suspended on a driver for which VFS issued a grant. Find out
212 * which process it was.
215 for (rfp
= &fproc
[0]; rfp
< &fproc
[NR_PROCS
]; rfp
++) {
216 if(rfp
->fp_pid
== PID_FREE
)
219 if(rfp
->fp_blocked_on
== FP_BLOCKED_ON_OTHER
&&
220 rfp
->fp_task
== driver
&& rfp
->fp_grant
== g
)
221 return(rfp
->fp_endpoint
);
228 /*===========================================================================*
230 *===========================================================================*/
231 void dev_status(endpoint_t drv_e
)
233 /* A device sent us a notification it has something for us. Retrieve it. */
236 int major
, get_more
= 1;
239 for (major
= 0; major
< NR_DEVICES
; major
++)
240 if (dmap_driver_match(drv_e
, major
))
241 break; /* 'major' is the device that sent the message */
243 if (major
>= NR_DEVICES
) /* Device endpoint not found; nothing to do */
246 if (dev_style_asyn(dmap
[major
].dmap_style
)) {
247 printf("VFS: not doing dev_status for async driver %d\n", drv_e
);
251 /* Continuously send DEV_STATUS messages until the device has nothing to
252 * say to us anymore. */
255 st
.m_type
= DEV_STATUS
;
256 r
= drv_sendrec(drv_e
, &st
);
257 if (r
== OK
&& st
.REP_STATUS
== ERESTART
) r
= EDEADEPT
;
259 printf("VFS: DEV_STATUS failed to %d: %d\n", drv_e
, r
);
260 if (r
== EDEADSRCDST
|| r
== EDEADEPT
) return;
261 panic("VFS: couldn't sendrec for DEV_STATUS: %d", r
);
266 /* We've got results for a read/write/ioctl call to a
267 * synchronous character driver */
268 endpt
= st
.REP_ENDPT
;
269 if (endpt
== VFS_PROC_NR
) {
270 endpt
= find_suspended_ep(drv_e
, st
.REP_IO_GRANT
);
272 printf("VFS: proc with grant %d from %d not found\n",
273 st
.REP_IO_GRANT
, st
.m_source
);
277 revive(endpt
, st
.REP_STATUS
);
280 /* Reply to a select request: driver is ready for I/O */
281 select_reply2(st
.m_source
, st
.DEV_MINOR
, st
.DEV_SEL_OPS
);
284 printf("VFS: unrecognized reply %d to DEV_STATUS\n",st
.m_type
);
293 /*===========================================================================*
294 * safe_io_conversion *
295 *===========================================================================*/
296 static int safe_io_conversion(driver
, gid
, op
, io_ept
, buf
, bytes
, pos_lo
)
305 /* Convert operation to the 'safe' variant (i.e., grant based) if applicable.
306 * If no copying of data is involved, there is also no need to convert. */
311 *gid
= GRANT_INVALID
; /* Grant to buffer */
316 /* Change to safe op. */
317 *op
= (*op
== VFS_DEV_READ
) ? DEV_READ_S
: DEV_WRITE_S
;
318 *gid
= cpf_grant_magic(driver
, *io_ept
, (vir_bytes
) *buf
, bytes
,
319 *op
== DEV_READ_S
? CPF_WRITE
: CPF_READ
);
321 panic("VFS: cpf_grant_magic of READ/WRITE buffer failed");
324 *pos_lo
= *io_ept
; /* Old endpoint in POSITION field. */
326 /* For IOCTLs, the bytes parameter encodes requested access method
328 if(_MINIX_IOCTL_IOR(bytes
)) access
|= CPF_WRITE
;
329 if(_MINIX_IOCTL_IOW(bytes
)) access
|= CPF_READ
;
330 if(_MINIX_IOCTL_BIG(bytes
))
331 size
= _MINIX_IOCTL_SIZE_BIG(bytes
);
333 size
= _MINIX_IOCTL_SIZE(bytes
);
335 /* Grant access to the buffer even if no I/O happens with the ioctl, in
336 * order to disambiguate requests with DEV_IOCTL_S.
338 *gid
= cpf_grant_magic(driver
, *io_ept
, (vir_bytes
) *buf
, size
, access
);
340 panic("VFS: cpf_grant_magic IOCTL buffer failed");
347 panic("VFS: unknown operation %d for safe I/O conversion", *op
);
350 /* If we have converted to a safe operation, I/O endpoint becomes VFS if it
353 if(GRANT_VALID(*gid
)) {
354 *io_ept
= VFS_PROC_NR
;
358 /* Not converted to a safe operation (because there is no copying involved in
364 static int cancel_nblock(struct dmap
* dp
,
372 dev_mess
.m_type
= CANCEL
;
373 dev_mess
.USER_ENDPT
= ioproc
;
374 dev_mess
.IO_GRANT
= (char *) gid
;
376 /* This R_BIT/W_BIT check taken from suspend()/unpause()
377 * logic. Mode is expected in the COUNT field.
381 dev_mess
.COUNT
= R_BIT
;
382 else if (call
== WRITE
)
383 dev_mess
.COUNT
= W_BIT
;
384 dev_mess
.DEVICE
= minor
;
385 (*dp
->dmap_io
)(dp
->dmap_driver
, &dev_mess
);
387 return dev_mess
.REP_STATUS
;
390 /*===========================================================================*
392 *===========================================================================*/
394 int op
, /* DEV_READ, DEV_WRITE, DEV_IOCTL, etc. */
395 dev_t dev
, /* major-minor device number */
396 int proc_e
, /* in whose address space is buf? */
397 void *buf
, /* virtual address of the buffer */
398 u64_t pos
, /* byte position */
399 size_t bytes
, /* how many bytes to transfer */
400 int flags
, /* special flags, like O_NONBLOCK */
401 int suspend_reopen
/* Just suspend the process */
404 /* Read from or write to a device. The parameter 'dev' tells which one. */
406 u32_t pos_lo
, pos_high
;
408 cp_grant_id_t gid
= GRANT_INVALID
;
409 int safe
, minor_dev
, major_dev
;
414 pos_lo
= ex64lo(pos
);
415 pos_high
= ex64hi(pos
);
416 major_dev
= major(dev
);
417 minor_dev
= minor(dev
);
419 /* Determine task dmap. */
420 dp
= &dmap
[major_dev
];
422 /* See if driver is roughly valid. */
423 if (dp
->dmap_driver
== NONE
) return(ENXIO
);
425 if (suspend_reopen
) {
427 fp
->fp_grant
= GRANT_INVALID
;
428 fp
->fp_ioproc
= NONE
;
429 wait_for(dp
->dmap_driver
);
430 fp
->fp_flags
|= FP_SUSP_REOPEN
;
434 if(isokendpt(dp
->dmap_driver
, &dummyproc
) != OK
) {
435 printf("VFS: dev_io: old driver for major %x (%d)\n", major_dev
,
440 /* By default, these are right. */
441 dev_mess
.USER_ENDPT
= proc_e
;
442 dev_mess
.ADDRESS
= buf
;
444 /* Convert DEV_* to DEV_*_S variants. */
446 safe
= safe_io_conversion(dp
->dmap_driver
, &gid
, &op
,
447 (endpoint_t
*) &dev_mess
.USER_ENDPT
, &buf_used
,
450 is_asyn
= dev_style_asyn(dp
->dmap_style
);
452 /* If the safe conversion was done, set the IO_GRANT to
455 if(safe
) dev_mess
.IO_GRANT
= (char *) gid
;
457 /* Set up the rest of the message passed to task. */
458 dev_mess
.m_type
= op
;
459 dev_mess
.DEVICE
= minor_dev
;
460 dev_mess
.POSITION
= pos_lo
;
461 dev_mess
.COUNT
= bytes
;
462 dev_mess
.HIGHPOS
= pos_high
;
465 if (flags
& O_NONBLOCK
)
466 dev_mess
.FLAGS
|= FLG_OP_NONBLOCK
;
468 /* This will be used if the i/o is suspended. */
469 ioproc
= dev_mess
.USER_ENDPT
;
472 (*dp
->dmap_io
)(dp
->dmap_driver
, &dev_mess
);
474 if(dp
->dmap_driver
== NONE
) {
475 /* Driver has vanished. */
476 printf("VFS: driver gone?!\n");
477 if(safe
) cpf_revoke(gid
);
481 ret
= dev_mess
.REP_STATUS
;
483 /* Task has completed. See if call completed. */
484 if (ret
== SUSPEND
) {
485 if ((flags
& O_NONBLOCK
) && !is_asyn
) {
486 /* Not supposed to block. */
487 ret
= cancel_nblock(dp
, minor_dev
, job_call_nr
, ioproc
, gid
);
491 /* select() will do suspending itself. */
492 if(op
!= DEV_SELECT
) {
494 wait_for(dp
->dmap_driver
);
496 assert(!GRANT_VALID(fp
->fp_grant
));
497 fp
->fp_grant
= gid
; /* revoke this when unsuspended. */
498 fp
->fp_ioproc
= ioproc
;
500 if ((flags
& O_NONBLOCK
) && !is_asyn
) {
501 /* Not supposed to block, send cancel message */
502 cancel_nblock(dp
, minor_dev
, job_call_nr
, ioproc
, gid
);
504 * FIXME Should do something about EINTR -> EAGAIN
512 /* No suspend, or cancelled suspend, so I/O is over and can be cleaned up. */
513 if(safe
) cpf_revoke(gid
);
518 /*===========================================================================*
520 *===========================================================================*/
522 int op
, /* operation, (B)DEV_OPEN or (B)DEV_CLOSE */
523 dev_t dev
, /* device to open or close */
524 endpoint_t proc_e
, /* process to open/close for */
525 int flags
/* mode bits and flags */
528 /* Called from the dmap struct on opens & closes of special files.*/
529 int r
, minor_dev
, major_dev
, is_bdev
;
533 /* Determine task dmap. */
534 major_dev
= major(dev
);
535 minor_dev
= minor(dev
);
536 assert(major_dev
>= 0 && major_dev
< NR_DEVICES
);
537 dp
= &dmap
[major_dev
];
538 assert(dp
->dmap_driver
!= NONE
);
540 is_bdev
= IS_BDEV_RQ(op
);
543 memset(&dev_mess
, 0, sizeof(dev_mess
));
544 dev_mess
.m_type
= op
;
545 dev_mess
.BDEV_MINOR
= minor_dev
;
546 dev_mess
.BDEV_ACCESS
= flags
;
547 dev_mess
.BDEV_ID
= 0;
549 dev_mess
.m_type
= op
;
550 dev_mess
.DEVICE
= minor_dev
;
551 dev_mess
.USER_ENDPT
= proc_e
;
552 dev_mess
.COUNT
= flags
;
556 r
= (*dp
->dmap_io
)(dp
->dmap_driver
, &dev_mess
);
557 if (r
!= OK
) return(r
);
559 if (op
== DEV_OPEN
&& dp
->dmap_style
== STYLE_DEVA
) {
560 fp
->fp_task
= dp
->dmap_driver
;
565 return(dev_mess
.BDEV_STATUS
);
567 return(dev_mess
.REP_STATUS
);
570 /*===========================================================================*
572 *===========================================================================*/
574 int op
, /* operation, DEV_OPEN or DEV_CLOSE */
575 dev_t dev
, /* device to open or close */
576 endpoint_t proc_e
, /* process to open/close for */
577 int flags
/* mode bits and flags */
580 /* This procedure is called from the dmap struct on tty open/close. */
583 register struct fproc
*rfp
;
585 assert(!IS_BDEV_RQ(op
));
587 /* Add O_NOCTTY to the flags if this process is not a session leader, or
588 * if it already has a controlling tty, or if it is someone elses
591 if (!(fp
->fp_flags
& FP_SESLDR
) || fp
->fp_tty
!= 0) {
594 for (rfp
= &fproc
[0]; rfp
< &fproc
[NR_PROCS
]; rfp
++) {
595 if(rfp
->fp_pid
== PID_FREE
) continue;
596 if (rfp
->fp_tty
== dev
) flags
|= O_NOCTTY
;
600 r
= gen_opcl(op
, dev
, proc_e
, flags
);
602 /* Did this call make the tty the controlling tty? */
612 /*===========================================================================*
614 *===========================================================================*/
616 int op
, /* operation, DEV_OPEN or DEV_CLOSE */
617 dev_t
UNUSED(dev
), /* device to open or close */
618 endpoint_t
UNUSED(proc_e
), /* process to open/close for */
619 int UNUSED(flags
) /* mode bits and flags */
622 /* This procedure is called from the dmap struct on opening or closing
623 * /dev/tty, the magic device that translates to the controlling tty.
627 panic("ctty_opcl() called for block device request?");
629 return(fp
->fp_tty
== 0 ? ENXIO
: OK
);
633 /*===========================================================================*
635 *===========================================================================*/
636 void pm_setsid(endpoint_t proc_e
)
638 /* Perform the VFS side of the SETSID call, i.e. get rid of the controlling
639 * terminal of a process, and make the process a session leader.
641 register struct fproc
*rfp
;
644 /* Make the process a session leader with no controlling tty. */
645 okendpt(proc_e
, &slot
);
647 rfp
->fp_flags
|= FP_SESLDR
;
652 /*===========================================================================*
654 *===========================================================================*/
657 /* Perform the ioctl(ls_fd, request, argx) system call */
659 int r
= OK
, suspend_reopen
, ioctlrequest
;
661 register struct vnode
*vp
;
665 scratch(fp
).file
.fd_nr
= job_m_in
.ls_fd
;
666 ioctlrequest
= job_m_in
.REQUEST
;
667 argx
= job_m_in
.ADDRESS
;
669 if ((f
= get_filp(scratch(fp
).file
.fd_nr
, VNODE_READ
)) == NULL
)
671 vp
= f
->filp_vno
; /* get vnode pointer */
672 if (!S_ISCHR(vp
->v_mode
) && !S_ISBLK(vp
->v_mode
)) {
677 suspend_reopen
= (f
->filp_state
& FS_NEEDS_REOPEN
);
678 dev
= (dev_t
) vp
->v_sdev
;
680 if (S_ISBLK(vp
->v_mode
))
681 r
= bdev_ioctl(dev
, who_e
, ioctlrequest
, argx
);
683 r
= dev_io(VFS_DEV_IOCTL
, dev
, who_e
, argx
, cvu64(0),
684 ioctlrequest
, f
->filp_flags
, suspend_reopen
);
693 /*===========================================================================*
695 *===========================================================================*/
696 int gen_io(driver_e
, mess_ptr
)
697 endpoint_t driver_e
; /* which endpoint to call */
698 message
*mess_ptr
; /* pointer to message for task */
700 /* All file system I/O ultimately comes down to I/O on major/minor device
701 * pairs. These lead to calls on the following routines via the dmap table.
703 int r
, status
, proc_e
= NONE
, is_bdev
, retry_count
;
706 is_bdev
= IS_BDEV_RQ(mess_ptr
->m_type
);
707 mess_retry
= *mess_ptr
;
710 if (!is_bdev
) proc_e
= mess_ptr
->USER_ENDPT
;
713 r
= drv_sendrec(driver_e
, mess_ptr
);
716 status
= mess_ptr
->BDEV_STATUS
;
718 status
= mess_ptr
->REP_STATUS
;
719 if (status
== ERESTART
) {
721 *mess_ptr
= mess_retry
;
725 } while (r
== EDEADEPT
&& retry_count
< 5);
728 if (r
== EDEADSRCDST
|| r
== EDEADEPT
) {
729 printf("VFS: dead driver %d\n", driver_e
);
730 dmap_unmap_by_endpt(driver_e
);
732 } else if (r
== ELOCKED
) {
733 printf("VFS: ELOCKED talking to %d\n", driver_e
);
736 panic("call_task: can't send/receive: %d", r
);
739 /* Did the process we did the sendrec() for get a result? */
740 if (!is_bdev
&& mess_ptr
->REP_ENDPT
!= proc_e
&& mess_ptr
->m_type
!= EIO
) {
741 printf("VFS: strange device reply from %d, type = %d, "
742 "proc = %d (not %d) (2) ignored\n", mess_ptr
->m_source
,
743 mess_ptr
->m_type
, proc_e
, mess_ptr
->REP_ENDPT
);
746 } else if (!IS_DRV_REPLY(mess_ptr
->m_type
))
753 /*===========================================================================*
755 *===========================================================================*/
756 int asyn_io(endpoint_t drv_e
, message
*mess_ptr
)
758 /* All file system I/O ultimately comes down to I/O on major/minor device
759 * pairs. These lead to calls on the following routines via the dmap table.
764 assert(!IS_BDEV_RQ(mess_ptr
->m_type
));
765 self
->w_drv_sendrec
= mess_ptr
; /* Remember where result should be stored */
766 self
->w_task
= drv_e
;
768 r
= asynsend3(drv_e
, mess_ptr
, AMF_NOREPLY
);
770 if (r
!= OK
) panic("VFS: asynsend in asyn_io failed: %d", r
);
773 mess_ptr
->REP_STATUS
= SUSPEND
;
778 /*===========================================================================*
780 *===========================================================================*/
782 endpoint_t
UNUSED(task_nr
), /* not used - for compatibility with dmap_t */
783 message
*mess_ptr
/* pointer to message for task */
786 /* This routine is only called for one device, namely /dev/tty. Its job
787 * is to change the message to use the controlling terminal, instead of the
788 * major/minor pair for /dev/tty itself.
793 if (fp
->fp_tty
== 0) {
794 /* No controlling tty present anymore, return an I/O error. */
795 mess_ptr
->REP_STATUS
= EIO
;
797 /* Substitute the controlling terminal device. */
798 dp
= &dmap
[major(fp
->fp_tty
)];
799 mess_ptr
->DEVICE
= minor(fp
->fp_tty
);
801 if (dp
->dmap_driver
== NONE
) {
802 printf("FS: ctty_io: no driver for dev\n");
806 if (isokendpt(dp
->dmap_driver
, &dummyproc
) != OK
) {
807 printf("VFS: ctty_io: old driver %d\n", dp
->dmap_driver
);
811 (*dp
->dmap_io
)(dp
->dmap_driver
, mess_ptr
);
818 /*===========================================================================*
820 *===========================================================================*/
822 int UNUSED(op
), /* operation, DEV_OPEN or DEV_CLOSE */
823 dev_t
UNUSED(dev
), /* device to open or close */
824 int UNUSED(proc
), /* process to open/close for */
825 int UNUSED(flags
) /* mode bits and flags */
828 /* Called when opening a nonexistent device. */
832 /*===========================================================================*
834 *===========================================================================*/
835 int no_dev_io(endpoint_t
UNUSED(proc
), message
*UNUSED(m
))
837 /* Called when doing i/o on a nonexistent device. */
838 printf("VFS: I/O on unmapped device number\n");
843 /*===========================================================================*
845 *===========================================================================*/
847 int op
, /* operation, DEV_OPEN or DEV_CLOSE */
848 dev_t dev
, /* device to open or close */
849 int proc_e
, /* process to open/close for */
850 int flags
/* mode bits and flags */
853 /* Some devices need special processing upon open. Such a device is "cloned",
854 * i.e. on a succesful open it is replaced by a new device with a new unique
855 * minor device number. This new device number identifies a new object (such
856 * as a new network connection) that has been allocated within a task.
859 int r
, minor_dev
, major_dev
;
862 assert(!IS_BDEV_RQ(op
));
864 /* Determine task dmap. */
865 minor_dev
= minor(dev
);
866 major_dev
= major(dev
);
867 assert(major_dev
>= 0 && major_dev
< NR_DEVICES
);
868 dp
= &dmap
[major_dev
];
869 assert(dp
->dmap_driver
!= NONE
);
871 dev_mess
.m_type
= op
;
872 dev_mess
.DEVICE
= minor_dev
;
873 dev_mess
.USER_ENDPT
= proc_e
;
874 dev_mess
.COUNT
= flags
;
876 if(isokendpt(dp
->dmap_driver
, &dummyproc
) != OK
) {
877 printf("VFS clone_opcl: bad driver endpoint for major %d (%d)\n",
878 major_dev
, dp
->dmap_driver
);
883 r
= (*dp
->dmap_io
)(dp
->dmap_driver
, &dev_mess
);
884 if (r
!= OK
) return(r
);
886 if (op
== DEV_OPEN
&& dev_style_asyn(dp
->dmap_style
)) {
887 /* Wait for reply when driver is asynchronous */
888 fp
->fp_task
= dp
->dmap_driver
;
892 if (op
== DEV_OPEN
&& dev_mess
.REP_STATUS
>= 0) {
893 if (dev_mess
.REP_STATUS
!= minor_dev
) {
895 struct node_details res
;
897 /* A new minor device number has been returned.
898 * Request PFS to create a temporary device file to hold it.
901 /* Device number of the new device. */
902 dev
= (dev
& ~(BYTE
<< MINOR
)) | (dev_mess
.REP_STATUS
<< MINOR
);
905 r
= req_newnode(PFS_PROC_NR
, fp
->fp_effuid
, fp
->fp_effgid
,
906 ALL_MODES
| I_CHAR_SPECIAL
, dev
, &res
);
908 (void) clone_opcl(DEV_CLOSE
, dev
, proc_e
, 0);
912 /* Drop old node and use the new values */
913 if ((vp
= get_free_vnode()) == NULL
)
915 lock_vnode(vp
, VNODE_OPCL
);
917 assert(FD_ISSET(scratch(fp
).file
.fd_nr
, &fp
->fp_filp_inuse
));
918 unlock_vnode(fp
->fp_filp
[scratch(fp
).file
.fd_nr
]->filp_vno
);
919 put_vnode(fp
->fp_filp
[scratch(fp
).file
.fd_nr
]->filp_vno
);
921 vp
->v_fs_e
= res
.fs_e
;
924 vp
->v_fs_e
= res
.fs_e
;
925 vp
->v_inode_nr
= res
.inode_nr
;
926 vp
->v_mode
= res
.fmode
;
930 fp
->fp_filp
[scratch(fp
).file
.fd_nr
]->filp_vno
= vp
;
932 dev_mess
.REP_STATUS
= OK
;
934 return(dev_mess
.REP_STATUS
);
938 /*===========================================================================*
940 *===========================================================================*/
941 void bdev_up(int maj
)
943 /* A new block device driver has been mapped in. This may affect both mounted
944 * file systems and open block-special files.
952 if (maj
< 0 || maj
>= NR_DEVICES
) panic("VFS: out-of-bound major");
953 label
= dmap
[maj
].dmap_label
;
956 /* For each block-special file that was previously opened on the affected
957 * device, we need to reopen it on the new driver.
959 for (rfilp
= filp
; rfilp
< &filp
[NR_FILPS
]; rfilp
++) {
960 if (rfilp
->filp_count
< 1 || !(vp
= rfilp
->filp_vno
)) continue;
961 if (major(vp
->v_sdev
) != maj
) continue;
962 if (!S_ISBLK(vp
->v_mode
)) continue;
964 /* Reopen the device on the driver, once per filp. */
965 bits
= mode_map
[rfilp
->filp_mode
& O_ACCMODE
];
966 if ((r
= bdev_open(vp
->v_sdev
, bits
)) != OK
) {
967 printf("VFS: mounted dev %d/%d re-open failed: %d.\n",
968 maj
, minor(vp
->v_sdev
), r
);
969 dmap
[maj
].dmap_recovering
= 0;
970 return; /* Give up entirely */
976 /* Tell each affected mounted file system about the new endpoint.
978 for (vmp
= &vmnt
[0]; vmp
< &vmnt
[NR_MNTS
]; ++vmp
) {
979 if (major(vmp
->m_dev
) != maj
) continue;
981 /* Send the driver label to the mounted file system. */
982 if (OK
!= req_newdriver(vmp
->m_fs_e
, vmp
->m_dev
, label
))
983 printf("VFS dev_up: error sending new driver label to %d\n",
987 /* If any block-special file was open for this major at all, also inform the
988 * root file system about the new driver. We do this even if the
989 * block-special file is linked to another mounted file system, merely
990 * because it is more work to check for that case.
993 if (OK
!= req_newdriver(ROOT_FS_E
, makedev(maj
, 0), label
))
994 printf("VFSdev_up: error sending new driver label to %d\n",
1001 /*===========================================================================*
1003 *===========================================================================*/
1004 void cdev_up(int maj
)
1006 /* A new character device driver has been mapped in.
1008 int needs_reopen
, fd_nr
;
1013 /* Look for processes that are suspended in an OPEN call. Set FP_SUSP_REOPEN
1014 * to indicate that this process was suspended before the call to dev_up.
1016 for (rfp
= &fproc
[0]; rfp
< &fproc
[NR_PROCS
]; rfp
++) {
1017 if(rfp
->fp_pid
== PID_FREE
) continue;
1018 if(rfp
->fp_blocked_on
!= FP_BLOCKED_ON_DOPEN
) continue;
1020 fd_nr
= scratch(rfp
).file
.fd_nr
;
1021 printf("VFS: dev_up: found process in FP_BLOCKED_ON_DOPEN, fd %d\n",
1023 rfilp
= rfp
->fp_filp
[fd_nr
];
1024 vp
= rfilp
->filp_vno
;
1025 if (!vp
) panic("VFS: cdev_up: no vp");
1026 if (!S_ISCHR(vp
->v_mode
)) continue;
1027 if (major(vp
->v_sdev
) != maj
) continue;
1029 rfp
->fp_flags
|= FP_SUSP_REOPEN
;
1032 needs_reopen
= FALSE
;
1033 for (rfilp
= filp
; rfilp
< &filp
[NR_FILPS
]; rfilp
++) {
1034 if (rfilp
->filp_count
< 1 || !(vp
= rfilp
->filp_vno
)) continue;
1035 if (major(vp
->v_sdev
) != maj
) continue;
1036 if (!S_ISCHR(vp
->v_mode
)) continue;
1038 rfilp
->filp_state
|= FS_NEEDS_REOPEN
;
1039 needs_reopen
= TRUE
;
1043 restart_reopen(maj
);
1046 /*===========================================================================*
1048 *===========================================================================*/
1049 void open_reply(void)
1052 struct worker_thread
*wp
;
1056 proc_e
= job_m_in
.REP_ENDPT
;
1057 if (isokendpt(proc_e
, &slot
) != OK
) return;
1059 wp
= worker_get(rfp
->fp_wtid
);
1060 if (wp
== NULL
|| wp
->w_task
!= who_e
) {
1061 printf("VFS: no worker thread waiting for a reply from %d\n", who_e
);
1064 *wp
->w_drv_sendrec
= job_m_in
;
1065 wp
->w_drv_sendrec
= NULL
;
1067 worker_signal(wp
); /* Continue open */
1070 /*===========================================================================*
1072 *===========================================================================*/
1073 void dev_reply(struct dmap
*dp
)
1075 struct worker_thread
*wp
;
1078 assert(dp
->dmap_servicing
!= NONE
);
1080 wp
= worker_get(dp
->dmap_servicing
);
1081 if (wp
== NULL
|| wp
->w_task
!= who_e
) {
1082 printf("VFS: no worker thread waiting for a reply from %d\n",
1087 assert(wp
->w_drv_sendrec
!= NULL
);
1088 *wp
->w_drv_sendrec
= m_in
;
1089 wp
->w_drv_sendrec
= NULL
;
1093 /*===========================================================================*
1095 *===========================================================================*/
1096 static void restart_reopen(maj
)
1099 int n
, r
, minor_dev
, major_dev
, fd_nr
;
1100 endpoint_t driver_e
;
1105 if (maj
< 0 || maj
>= NR_DEVICES
) panic("VFS: out-of-bound major");
1106 for (rfilp
= filp
; rfilp
< &filp
[NR_FILPS
]; rfilp
++) {
1107 if (rfilp
->filp_count
< 1 || !(vp
= rfilp
->filp_vno
)) continue;
1108 if (!(rfilp
->filp_state
& FS_NEEDS_REOPEN
)) continue;
1109 if (!S_ISCHR(vp
->v_mode
)) continue;
1111 major_dev
= major(vp
->v_sdev
);
1112 minor_dev
= minor(vp
->v_sdev
);
1113 if (major_dev
!= maj
) continue;
1115 if (rfilp
->filp_flags
& O_REOPEN
) {
1116 /* Try to reopen a file upon driver restart */
1117 r
= dev_reopen(vp
->v_sdev
, rfilp
-filp
,
1118 vp
->v_mode
& (R_BIT
|W_BIT
));
1123 printf("VFS: file on dev %d/%d re-open failed: %d\n",
1124 major_dev
, minor_dev
, r
);
1127 /* File descriptor is to be closed when driver restarts. */
1128 n
= invalidate_filp(rfilp
);
1129 if (n
!= rfilp
->filp_count
) {
1130 printf("VFS: warning: invalidate/count "
1131 "discrepancy (%d, %d)\n", n
, rfilp
->filp_count
);
1133 rfilp
->filp_count
= 0;
1135 /* We have to clean up this filp and vnode, but can't do that yet as
1136 * it's locked by a worker thread. Start a new job to garbage collect
1137 * invalidated filps associated with this device driver.
1139 sys_worker_start(do_filp_gc
);
1142 /* Nothing more to re-open. Restart suspended processes */
1143 driver_e
= dmap
[maj
].dmap_driver
;
1145 for (rfp
= &fproc
[0]; rfp
< &fproc
[NR_PROCS
]; rfp
++) {
1146 if(rfp
->fp_pid
== PID_FREE
) continue;
1147 if(rfp
->fp_blocked_on
== FP_BLOCKED_ON_OTHER
&&
1148 rfp
->fp_task
== driver_e
&& (rfp
->fp_flags
& FP_SUSP_REOPEN
)) {
1149 rfp
->fp_flags
&= ~FP_SUSP_REOPEN
;
1150 rfp
->fp_blocked_on
= FP_BLOCKED_ON_NONE
;
1151 reply(rfp
->fp_endpoint
, ERESTART
);
1155 /* Look for processes that are suspened in an OPEN call */
1156 for (rfp
= &fproc
[0]; rfp
< &fproc
[NR_PROCS
]; rfp
++) {
1157 if (rfp
->fp_pid
== PID_FREE
) continue;
1158 if (rfp
->fp_blocked_on
== FP_BLOCKED_ON_DOPEN
||
1159 !(rfp
->fp_flags
& FP_SUSP_REOPEN
)) continue;
1161 fd_nr
= scratch(rfp
).file
.fd_nr
;
1162 printf("VFS: restart_reopen: process in FP_BLOCKED_ON_DOPEN fd=%d\n",
1164 rfilp
= rfp
->fp_filp
[fd_nr
];
1167 /* Open failed, and automatic reopen was not requested */
1168 rfp
->fp_blocked_on
= FP_BLOCKED_ON_NONE
;
1169 FD_CLR(fd_nr
, &rfp
->fp_filp_inuse
);
1170 reply(rfp
->fp_endpoint
, EIO
);
1174 vp
= rfilp
->filp_vno
;
1175 if (!vp
) panic("VFS: restart_reopen: no vp");
1176 if (!S_ISCHR(vp
->v_mode
)) continue;
1177 if (major(vp
->v_sdev
) != maj
) continue;
1179 rfp
->fp_blocked_on
= FP_BLOCKED_ON_NONE
;
1180 reply(rfp
->fp_endpoint
, fd_nr
);
1185 /*===========================================================================*
1187 *===========================================================================*/
1190 endpoint_t driver_e
;
1191 int filp_no
, status
, maj
;
1196 driver_e
= job_m_in
.m_source
;
1197 filp_no
= job_m_in
.REP_ENDPT
;
1198 status
= job_m_in
.REP_STATUS
;
1200 if (filp_no
< 0 || filp_no
>= NR_FILPS
) {
1201 printf("VFS: reopen_reply: bad filp number %d from driver %d\n",
1206 rfilp
= &filp
[filp_no
];
1207 if (rfilp
->filp_count
< 1) {
1208 printf("VFS: reopen_reply: filp number %d not inuse (from driver %d)\n",
1213 vp
= rfilp
->filp_vno
;
1215 printf("VFS: reopen_reply: no vnode for filp number %d (from driver "
1216 "%d)\n", filp_no
, driver_e
);
1220 if (!(rfilp
->filp_state
& FS_NEEDS_REOPEN
)) {
1221 printf("VFS: reopen_reply: bad state %d for filp number %d"
1222 " (from driver %d)\n", rfilp
->filp_state
, filp_no
, driver_e
);
1226 if (!S_ISCHR(vp
->v_mode
)) {
1227 printf("VFS: reopen_reply: bad mode 0%o for filp number %d"
1228 " (from driver %d)\n", vp
->v_mode
, filp_no
, driver_e
);
1232 maj
= major(vp
->v_sdev
);
1234 if (dp
->dmap_driver
!= driver_e
) {
1235 printf("VFS: reopen_reply: bad major %d for filp number %d "
1236 "(from driver %d, current driver is %d)\n", maj
, filp_no
,
1237 driver_e
, dp
->dmap_driver
);
1242 rfilp
->filp_state
&= ~FS_NEEDS_REOPEN
;
1244 printf("VFS: reopen_reply: should handle error status\n");
1248 restart_reopen(maj
);