From: Ben Gras Date: Thu, 20 Oct 2005 19:39:32 +0000 (+0000) Subject: Two 'dynamic driver' features in FS: X-Git-Tag: v3.1.2a~601 X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/icons/zpipe.c?a=commitdiff_plain;h=b5e3e6d18c0d471bdd5bebdaed3e9c9694d409fa;p=minix.git 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. --- diff --git a/servers/fs/device.c b/servers/fs/device.c index 9909a8911..50e443065 100644 --- a/servers/fs/device.c +++ b/servers/fs/device.c @@ -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; +} + diff --git a/servers/fs/dmap.c b/servers/fs/dmap.c index 526cac21d..5513cc156 100644 --- a/servers/fs/dmap.c +++ b/servers/fs/dmap.c @@ -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; ifp_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. diff --git a/servers/fs/pipe.c b/servers/fs/pipe.c index ec9855f51..a1c870ad1 100644 --- a/servers/fs/pipe.c +++ b/servers/fs/pipe.c @@ -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; } diff --git a/servers/fs/proto.h b/servers/fs/proto.h index 474880e32..705f4692c 100644 --- a/servers/fs/proto.h +++ b/servers/fs/proto.h @@ -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 */ diff --git a/servers/fs/select.c b/servers/fs/select.c index 3873cea3b..b361ee52d 100644 --- a/servers/fs/select.c +++ b/servers/fs/select.c @@ -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; +} +