Two 'dynamic driver' features in FS:

.  When drivers disappear that have pending select()s, wake up
   those user processes with EAGAIN so that they can retry their
   select() and won't hang forever on it.
.  When drivers re-appear and are mapped into the dmap, run through
   the list of mounted filesystems and re-dev_open() every one (for
   partition tables and such). This can't happen before the driver
   has exec()ced itself, so processes that have fork()ed but not
   exec()ced yet are marked as DMAP_BABY in the dmap table if they
   are dmapped before they are execced. If that happens, the above
   procedure happens after the exec(). If the exec() happens before
   the dmapping, it (the dev_open()ing) happens right away.
This commit is contained in:
Ben Gras 2005-10-20 19:39:32 +00:00
parent 11146aba3d
commit b5e3e6d18c
7 changed files with 163 additions and 36 deletions

View file

@ -25,6 +25,7 @@
#include "fproc.h"
#include "inode.h"
#include "param.h"
#include "super.h"
#define ELEMENTS(a) (sizeof(a)/sizeof((a)[0]))
@ -51,7 +52,7 @@ int flags; /* mode bits and flags */
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);
}
@ -73,7 +74,8 @@ PUBLIC void dev_status(message *m)
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)
@ -82,8 +84,11 @@ PUBLIC void dev_status(message *m)
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:
@ -125,7 +130,7 @@ int flags; /* special flags, like O_NONBLOCK */
/* 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;
@ -480,3 +485,34 @@ int flags; /* mode bits and flags */
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;
}

View file

@ -126,6 +126,14 @@ int style; /* style of the device */
}
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);
}
@ -203,3 +211,31 @@ PUBLIC void build_dmap()
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;
}

View file

@ -20,6 +20,7 @@ EXTERN struct fproc {
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];

View file

@ -264,6 +264,9 @@ PUBLIC int do_fork()
/* 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);
@ -288,15 +291,25 @@ PUBLIC int do_exec()
/* 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;
}
/*===========================================================================*
@ -339,11 +352,13 @@ PUBLIC int do_exit()
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.

View file

@ -11,6 +11,7 @@
* 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
*/
@ -197,17 +198,22 @@ int task; /* who is proc waiting for? (PIPE = pipe) */
/*===========================================================================*
* 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;
}

View file

@ -42,6 +42,7 @@ _PROTOTYPE( void ctty_io, (int task_nr, message *mess_ptr) );
_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) );
@ -50,7 +51,9 @@ _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) );
@ -186,6 +189,7 @@ _PROTOTYPE( int select_callback, (struct filp *, int ops) );
_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 */

View file

@ -4,6 +4,7 @@
* 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)
@ -56,7 +57,8 @@ FORWARD _PROTOTYPE(int select_major_match,
(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
@ -458,14 +460,9 @@ PRIVATE void select_cancel_all(struct selectentry *e)
/*===========================================================================*
* 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);
}
/*===========================================================================*
@ -502,6 +499,17 @@ PRIVATE int select_reevaluate(struct filp *fp)
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 *
*===========================================================================*/
@ -535,12 +543,8 @@ PUBLIC int select_callback(struct filp *fp, int ops)
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;
@ -581,7 +585,9 @@ PUBLIC int select_notified(int major, int minor, int selected_ops)
!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));
@ -665,10 +671,33 @@ PUBLIC void select_timeout_check(timer_t *timer)
}
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;
}