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; +} +