]> Zhao Yanbai Git Server - minix.git/commitdiff
Two 'dynamic driver' features in FS:
authorBen Gras <ben@minix3.org>
Thu, 20 Oct 2005 19:39:32 +0000 (19:39 +0000)
committerBen Gras <ben@minix3.org>
Thu, 20 Oct 2005 19:39:32 +0000 (19:39 +0000)
.  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.

servers/fs/device.c
servers/fs/dmap.c
servers/fs/fproc.h
servers/fs/misc.c
servers/fs/pipe.c
servers/fs/proto.h
servers/fs/select.c

index 9909a8911bcef4653bb545119866cba7d4099432..50e4430653c2832ea463e374da1ec78775c6670a 100644 (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;
+}
+
index 526cac21dca12b893734a48b28345c8894318ea5..5513cc1563a78ba0f57366376d70adb3cb28510c 100644 (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;
+}
index 7747aa35bce08efc90f0f77aaff03a981f2d9316..fcd7c222a850ec3b1df85f80d814710dfc935429 100644 (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];
index 5bfbf1d566d9d052167ccd724940aae6ef04a7e4..4d39e9b5c44b879dcaf1e5cec2db181c74d478e5 100644 (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.
index ec9855f51afd3652c2a922c848df61ee6fafc263..a1c870ad1c1d8bcb1cf9a2fef8b51e53983f64b5 100644 (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;
 }
index 474880e3295e52b965543bd84491198877564796..705f4692cb236980e9109c4d77c8d89988c695ca 100644 (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 */
index 3873cea3b94ea5262dc688915adb2991d4d2537d..b361ee52d6fbea75f2441b208eade7d2cd020432 100644 (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;
+}
+