#include "fproc.h"
#include "inode.h"
#include "param.h"
+#include "super.h"
#define ELEMENTS(a) (sizeof(a)/sizeof((a)[0]))
r = (*dp->dmap_opcl)(DEV_OPEN, dev, proc, flags);
if (r == SUSPEND) panic(__FILE__,"suspend on open from", dp->dmap_driver);
if (r == OK && dp->dmap_driver == NONE)
- panic(__FILE__, "no driver for dev %d", dev);
+ panic(__FILE__, "no driver for dev", dev);
return(r);
}
int d, get_more = 1;
for(d = 0; d < NR_DEVICES; d++)
- if (dmap[d].dmap_driver == m->m_source)
+ if (dmap[d].dmap_driver != NONE &&
+ dmap[d].dmap_driver == m->m_source)
break;
if (d >= NR_DEVICES)
do {
int r;
st.m_type = DEV_STATUS;
- if ((r=sendrec(m->m_source, &st)) != OK)
+ if ((r=sendrec(m->m_source, &st)) != OK) {
+ printf("DEV_STATUS failed to %d: %d\n", m->m_source, r);
+ if (r == EDEADSRCDST) return;
panic(__FILE__,"couldn't sendrec for DEV_STATUS", r);
+ }
switch(st.m_type) {
case DEV_REVIVE:
/* See if driver is roughly valid. */
if (dp->dmap_driver == NONE)
- panic(__FILE__, "no driver for i/o on dev %d", dev);
+ panic(__FILE__, "no driver for i/o on dev", dev);
/* Set up the message passed to task. */
dev_mess.m_type = op;
return(dev_mess.REP_STATUS);
}
+/*===========================================================================*
+ * dev_up *
+ *===========================================================================*/
+PUBLIC void dev_up(int maj)
+{
+ /* A new device driver has been mapped in. This function
+ * checks if any filesystems are mounted on it, and if so,
+ * dev_open()s them so the filesystem can be reused.
+ */
+ struct super_block *sb;
+ int r;
+
+ printf("dev_up for %d..\n", maj);
+ for(sb = super_block; sb < &super_block[NR_SUPERS]; sb++) {
+ int minor;
+ if(sb->s_dev == NO_DEV)
+ continue;
+ if(((sb->s_dev >> MAJOR) & BYTE) != maj)
+ continue;
+ minor = ((sb->s_dev >> MINOR) & BYTE);
+ printf("FS: remounting dev %d/%d\n", maj, minor);
+ if((r = dev_open(sb->s_dev, FS_PROC_NR,
+ sb->s_rd_only ? R_BIT : (R_BIT|W_BIT))) != OK) {
+ printf("FS: mounted dev %d/%d re-open failed: %d.\n",
+ maj, minor, r);
+ } else printf("FS: mounted dev %d/%d re-opened\n", maj, minor);
+ }
+
+ return;
+}
+
}
dp->dmap_io = gen_io;
dp->dmap_driver = proc_nr;
+
+ /* If a driver has completed its exec(), it can be announced to be up. */
+ if(fproc[proc_nr].fp_execced) {
+ dev_up(major);
+ } else {
+ dp->dmap_flags |= DMAP_BABY;
+ }
+
return(OK);
}
driver, controller);
}
+/*===========================================================================*
+ * dmap_driver_match *
+ *===========================================================================*/
+PUBLIC int dmap_driver_match(int proc, int major)
+{
+ if (major < 0 || major >= NR_DEVICES) return(0);
+ if(dmap[major].dmap_driver != NONE && dmap[major].dmap_driver == proc)
+ return 1;
+ return 0;
+}
+
+/*===========================================================================*
+ * dmap_proc_up *
+ *===========================================================================*/
+PUBLIC void dmap_proc_up(int proc)
+{
+ int i;
+ for (i=0; i<NR_DEVICES; i++) {
+ if(dmap[i].dmap_driver != NONE
+ && dmap[i].dmap_driver == proc
+ && (dmap[i].dmap_flags & DMAP_BABY)) {
+ dmap[i].dmap_flags &= ~DMAP_BABY;
+ printf("FS: %d execced\n", proc);
+ dev_up(i);
+ }
+ }
+ return;
+}
char fp_revived; /* set to indicate process being revived */
char fp_task; /* which task is proc suspended on */
char fp_sesldr; /* true if proc is a session leader */
+ char fp_execced; /* true if proc has exec()ced after fork */
pid_t fp_pid; /* process id */
long fp_cloexec; /* bit map for POSIX Table 6-2 FD_CLOEXEC */
} fproc[NR_PROCS];
/* A child is not a process leader. */
cp->fp_sesldr = 0;
+ /* This child has not exec()ced yet. */
+ cp->fp_execced = 0;
+
/* Record the fact that both root and working dir have another user. */
dup_inode(cp->fp_rootdir);
dup_inode(cp->fp_workdir);
/* The array of FD_CLOEXEC bits is in the fp_cloexec bit map. */
fp = &fproc[m_in.slot1]; /* get_filp() needs 'fp' */
bitmap = fp->fp_cloexec;
- if (bitmap == 0) return(OK); /* normal case, no FD_CLOEXECs */
-
- /* Check the file desriptors one by one for presence of FD_CLOEXEC. */
- for (i = 0; i < OPEN_MAX; i++) {
- m_in.fd = i;
- if ( (bitmap >> i) & 01) (void) do_close();
+ if (bitmap) {
+ /* Check the file desriptors one by one for presence of FD_CLOEXEC. */
+ for (i = 0; i < OPEN_MAX; i++) {
+ m_in.fd = i;
+ if ( (bitmap >> i) & 01) (void) do_close();
+ }
}
- return(OK);
+ /* This child has now exec()ced. */
+ fp->fp_execced = 1;
+
+ /* Reply to caller (PM) directly. */
+ reply(who, OK);
+
+ /* Check if this is a driver that can now be useful. */
+ dmap_proc_up(fp - fproc);
+
+ /* Suppress reply to caller (caller already replied to). */
+ return SUSPEND;
}
/*===========================================================================*
fp->fp_rootdir = NIL_INODE;
fp->fp_workdir = NIL_INODE;
- /* If a driver exits, unmap its entries in the dmap table.
- * Also check if any process is SUSPENDed on it.
+ /* Check if any process is SUSPENDed on this driver.
+ * If a driver exits, unmap its entries in the dmap table.
+ * (unmapping has to be done after the first step, because the
+ * dmap table is used in the first step.)
*/
- dmap_unmap_by_proc(exitee);
unsuspend_by_proc(exitee);
+ dmap_unmap_by_proc(exitee);
/* If a session leader exits then revoke access to its controlling tty from
* all other processes using it.
* release: check to see if a suspended process can be released and do
* it
* revive: mark a suspended process as able to run again
+ * unsuspend_by_proc: revive all processes blocking on a given process
* do_unpause: a signal has been sent to a process; see if it suspended
*/
/*===========================================================================*
* unsuspend_by_proc *
*===========================================================================*/
-void unsuspend_by_proc(int proc)
+PUBLIC void unsuspend_by_proc(int proc)
{
struct fproc *rp;
int client = 0;
/* Revive processes waiting for drivers (SUSPENDed) that have
- * disappeared with return code EIO.
+ * disappeared with return code EAGAIN.
*/
for (rp = &fproc[0]; rp < &fproc[NR_PROCS]; rp++, client++)
if(rp->fp_suspended == SUSPENDED && rp->fp_task == -proc)
- revive(client, EIO);
+ revive(client, EAGAIN);
+
+ /* Revive processes waiting in drivers on select()s
+ * with EAGAIN too.
+ */
+ select_unsuspend_by_proc(proc);
return;
}
_PROTOTYPE( int do_ioctl, (void) );
_PROTOTYPE( int do_setsid, (void) );
_PROTOTYPE( void dev_status, (message *) );
+_PROTOTYPE( void dev_up, (int major) );
/* dmp.c */
_PROTOTYPE( int do_fkey_pressed, (void) );
_PROTOTYPE( int do_devctl, (void) );
_PROTOTYPE( void build_dmap, (void) );
_PROTOTYPE( int map_driver, (int major, int proc_nr, int dev_style) );
+_PROTOTYPE( int dmap_driver_match, (int proc, int major) );
_PROTOTYPE( void dmap_unmap_by_proc, (int proc_nr) );
+_PROTOTYPE( void dmap_proc_up, (int proc_nr) );
/* filedes.c */
_PROTOTYPE( struct filp *find_filp, (struct inode *rip, mode_t bits) );
_PROTOTYPE( void select_forget, (int fproc) );
_PROTOTYPE( void select_timeout_check, (timer_t *) );
_PROTOTYPE( void init_select, (void) );
+_PROTOTYPE( void select_unsuspend_by_proc, (int proc) );
_PROTOTYPE( int select_notified, (int major, int minor, int ops) );
/* timers.c */
* do_select: perform the SELECT system call
* select_callback: notify select system of possible fd operation
* select_notified: low-level entry for device notifying select
+ * select_unsuspend_by_proc: cancel a blocking select on exiting driver
*
* Changes:
* 6 june 2005 Created (Ben Gras)
(int match_major, struct filp *file));
FORWARD _PROTOTYPE(void select_cancel_all, (struct selectentry *e));
-FORWARD _PROTOTYPE(void select_wakeup, (struct selectentry *e));
+FORWARD _PROTOTYPE(void select_wakeup, (struct selectentry *e, int r));
+FORWARD _PROTOTYPE(void select_return, (struct selectentry *, int));
/* The Open Group:
* "The pselect() and select() functions shall support
/*===========================================================================*
* select_wakeup *
*===========================================================================*/
-PRIVATE void select_wakeup(struct selectentry *e)
+PRIVATE void select_wakeup(struct selectentry *e, int r)
{
- /* Open Group:
- * "Upon successful completion, the pselect() and select()
- * functions shall return the total number of bits
- * set in the bit masks."
- */
- revive(e->req_procnr, e->nreadyfds);
+ revive(e->req_procnr, r);
}
/*===========================================================================*
return remain_ops;
}
+/*===========================================================================*
+ * select_return *
+ *===========================================================================*/
+PRIVATE void select_return(struct selectentry *s, int r)
+{
+ select_cancel_all(s);
+ copy_fdsets(s);
+ select_wakeup(s, r ? r : s->nreadyfds);
+ s->requestor = NULL;
+}
+
/*===========================================================================*
* select_callback *
*===========================================================================*/
type = selecttab[s].type[fd];
}
}
- if (wakehim) {
- select_cancel_all(&selecttab[s]);
- copy_fdsets(&selecttab[s]);
- selecttab[s].requestor = NULL;
- select_wakeup(&selecttab[s]);
- }
+ if (wakehim)
+ select_return(&selecttab[s], 0);
}
return 0;
!select_major_match(major, selecttab[s].filps[f]))
continue;
ops = tab2ops(f, &selecttab[s]);
- s_minor = selecttab[s].filps[f]->filp_ino->i_zone[0] & BYTE;
+ s_minor =
+ (selecttab[s].filps[f]->filp_ino->i_zone[0] >> MINOR)
+ & BYTE;
if ((s_minor == minor) &&
(selected_ops & ops)) {
select_callback(selecttab[s].filps[f], (selected_ops & ops));
}
selecttab[s].expiry = 0;
- copy_fdsets(&selecttab[s]);
- select_cancel_all(&selecttab[s]);
- selecttab[s].requestor = NULL;
- select_wakeup(&selecttab[s]);
+ select_return(&selecttab[s], 0);
return;
}
+
+/*===========================================================================*
+ * select_unsuspend_by_proc *
+ *===========================================================================*/
+PUBLIC void select_unsuspend_by_proc(int proc)
+{
+ struct filp *fp;
+ int fd, s;
+
+ for(s = 0; s < MAXSELECTS; s++) {
+ if (!selecttab[s].requestor)
+ continue;
+ for(fd = 0; fd < selecttab[s].nfds; fd++) {
+ int maj;
+ if (!selecttab[s].filps[fd] || !selecttab[s].filps[fd]->filp_ino)
+ continue;
+ maj = (selecttab[s].filps[fd]->filp_ino->i_zone[0] >> MAJOR)&BYTE;
+ if(dmap_driver_match(proc, maj)) {
+ select_return(&selecttab[s], EAGAIN);
+ }
+ }
+ }
+
+ return;
+}
+