]> Zhao Yanbai Git Server - minix.git/commitdiff
Add support for survival of crashed FSs
authorThomas Veerman <thomas@minix3.org>
Thu, 19 Jan 2012 14:21:46 +0000 (14:21 +0000)
committerThomas Veerman <thomas@minix3.org>
Thu, 19 Jan 2012 14:21:46 +0000 (14:21 +0000)
When an FS crashes, VFS will clean up resources tied to that FS:
 - Pending requests to the FS are canceled (i.e., fail with EIO)
 - Threads waiting for a reply are stopped (i.e., fail with EIO)
 - Open files are marked invalid. Future operations on a file descriptor
   will cause EBADF errors.
 - vmnt entry is cleared, so in-flight system calls that got past the
   file descriptor check but not yet talking to the crashed FS, will
   fail with EIO.
 - The reference counter of the mount point is decreased, effectively
   removing the crashed FS from the file system tree. Descendants of
   this part of the tree are unreachable by means of a path, but can
   still be unmounted by feeding the block special file to unmount(2).

This patch also gets rid of the "not a known driver endpoint" messages
during shutdown.

servers/avfs/comm.c
servers/avfs/device.c
servers/avfs/filedes.c
servers/avfs/misc.c
servers/avfs/path.c
servers/avfs/proto.h
servers/avfs/vmnt.c

index 85b6d2f4922e93e6ac4cf5238478fe5a8edbb982..89b2e503c3be1c6b6ff1279961ab97ec2382387e 100644 (file)
@@ -49,6 +49,22 @@ PUBLIC void send_work(void)
        fs_sendmore(vmp);
 }
 
+/*===========================================================================*
+ *                             fs_cancel                                    *
+ *===========================================================================*/
+PUBLIC void fs_cancel(struct vmnt *vmp)
+{
+/* Cancel all pending requests for this vmp */
+  struct worker_thread *worker;
+
+  while ((worker = vmp->m_comm.c_req_queue) != NULL) {
+       vmp->m_comm.c_req_queue = worker->w_next;
+       worker->w_next = NULL;
+       sending--;
+       worker_stop(worker);
+  }
+}
+
 /*===========================================================================*
  *                             fs_sendmore                                  *
  *===========================================================================*/
@@ -80,8 +96,10 @@ PUBLIC int fs_sendrec(endpoint_t fs_e, message *reqmp)
   struct vmnt *vmp;
   int r;
 
-  if ((vmp = find_vmnt(fs_e)) == NULL)
-       panic("Trying to talk to non-existent FS");
+  if ((vmp = find_vmnt(fs_e)) == NULL) {
+       printf("Trying to talk to non-existent FS endpoint %d\n", fs_e);
+       return(EIO);
+  }
   if (fs_e == fp->fp_endpoint) return(EDEADLK);
 
   if (!force_sync) {
index 29130df29a02e2242961e6c762f397fdb5e83451..969ac8b7df83e8b776ef9dbb0848b1d417b69fe3 100644 (file)
@@ -990,7 +990,7 @@ PUBLIC void cdev_up(int maj)
                fd_nr);
        rfilp = rfp->fp_filp[fd_nr];
        vp = rfilp->filp_vno;
-       if (!vp) panic("VFS: restart_reopen: no vp");
+       if (!vp) panic("VFS: cdev_up: no vp");
        if ((vp->v_mode &  I_TYPE) != I_CHAR_SPECIAL) continue;
        if (major(vp->v_sdev) != maj) continue;
 
@@ -1051,7 +1051,7 @@ int maj;
 
        if (!(rfilp->filp_flags & O_REOPEN)) {
                /* File descriptor is to be closed when driver restarts. */
-               n = invalidate(rfilp);
+               n = invalidate_filp(rfilp);
                if (n != rfilp->filp_count) {
                        printf("VFS: warning: invalidate/count "
                               "discrepancy (%d, %d)\n", n, rfilp->filp_count);
@@ -1064,7 +1064,7 @@ int maj;
        if (r == OK) return;
 
        /* Device could not be reopened. Invalidate all filps on that device.*/
-       n = invalidate(rfilp);
+       n = invalidate_filp(rfilp);
        if (n != rfilp->filp_count) {
                printf("VFS: warning: invalidate/count "
                        "discrepancy (%d, %d)\n", n, rfilp->filp_count);
index 83a432c1b0556f027aaf2fbf85ecc96ecf1cdaac..681030623b5d16f4328651d63c5ea61c1cf10846 100644 (file)
@@ -201,18 +201,18 @@ PUBLIC struct filp *find_filp(struct vnode *vp, mode_t bits)
 }
 
 /*===========================================================================*
- *                             invalidate                                   *
+ *                             invalidate_filp                              *
  *===========================================================================*/
-PUBLIC int invalidate(struct filp *fp)
+PUBLIC int invalidate_filp(struct filp *rfilp)
 {
 /* Invalidate filp. fp_filp_inuse is not cleared, so filp can't be reused
    until it is closed first. */
 
   int f, fd, n = 0;
-  for(f = 0; f < NR_PROCS; f++) {
-       if(fproc[f].fp_pid == PID_FREE) continue;
-       for(fd = 0; fd < OPEN_MAX; fd++) {
-               if(fproc[f].fp_filp[fd] && fproc[f].fp_filp[fd] == fp) {
+  for (f = 0; f < NR_PROCS; f++) {
+       if (fproc[f].fp_pid == PID_FREE) continue;
+       for (fd = 0; fd < OPEN_MAX; fd++) {
+               if(fproc[f].fp_filp[fd] && fproc[f].fp_filp[fd] == rfilp) {
                        fproc[f].fp_filp[fd] = NULL;
                        n++;
                }
@@ -222,6 +222,21 @@ PUBLIC int invalidate(struct filp *fp)
   return(n);   /* Report back how often this filp has been invalidated. */
 }
 
+/*===========================================================================*
+ *                     invalidate_filp_by_endpt                             *
+ *===========================================================================*/
+PUBLIC void invalidate_filp_by_endpt(endpoint_t proc_e)
+{
+  struct filp *f;
+
+  for (f = &filp[0]; f < &filp[NR_FILPS]; f++) {
+       if (f->filp_count != 0 && f->filp_vno != NULL) {
+               if (f->filp_vno->v_fs_e == proc_e)
+                       (void) invalidate_filp(f);
+       }
+  }
+}
+
 /*===========================================================================*
  *                             lock_filp                                    *
  *===========================================================================*/
index 31a8af2b8493307a8a912fec2996ea2e472a1a20..ed866016b229d6483a2cc457c3d5c168f11824cc 100644 (file)
@@ -450,6 +450,13 @@ PRIVATE void free_proc(struct fproc *exiter, int flags)
        (void) close_fd(exiter, i);
   }
 
+  /* Release root and working directories. */
+  if (exiter->fp_rd) { put_vnode(exiter->fp_rd); exiter->fp_rd = NULL; }
+  if (exiter->fp_wd) { put_vnode(exiter->fp_wd); exiter->fp_wd = NULL; }
+
+  /* The rest of these actions is only done when processes actually exit. */
+  if (!(flags & FP_EXITING)) return;
+
   /* 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
@@ -457,14 +464,10 @@ PRIVATE void free_proc(struct fproc *exiter, int flags)
    */
   unsuspend_by_endpt(exiter->fp_endpoint);
   dmap_unmap_by_endpt(exiter->fp_endpoint);
-  worker_stop_by_endpt(exiter->fp_endpoint);
 
-  /* Release root and working directories. */
-  if (exiter->fp_rd) { put_vnode(exiter->fp_rd); exiter->fp_rd = NULL; }
-  if (exiter->fp_wd) { put_vnode(exiter->fp_wd); exiter->fp_wd = NULL; }
-
-  /* The rest of these actions is only done when processes actually exit. */
-  if (!(flags & FP_EXITING)) return;
+  worker_stop_by_endpt(exiter->fp_endpoint); /* Unblock waiting threads */
+  vmnt_unmap_by_endpt(exiter->fp_endpoint); /* Invalidate open files if this
+                                            * was an active FS */
 
   /* Invalidate endpoint number for error and sanity checks. */
   exiter->fp_endpoint = NONE;
index 2ac2eece068e91ead843ac24b1cdad7be63949cf..d33f711a8a4363abd3c5c144bfe365189d34699b 100644 (file)
@@ -210,6 +210,11 @@ struct fproc *rfp;
                struct vmnt *vmp;
 
                vmp = find_vmnt(start_dir->v_fs_e);
+               if (vmp == NULL) {
+                       r = EIO;
+                       res_vp = NULL;
+                       break;
+               }
                r = lock_vmnt(vmp, resolve->l_vmnt_lock);
                if (r == EDEADLK) {
                        res_vp = NULL;
@@ -390,6 +395,8 @@ struct fproc *rfp;
   dir_ino = start_node->v_inode_nr;
   vmpres = find_vmnt(fs_e);
 
+  if (vmpres == NULL) return(EIO);     /* mountpoint vanished? */
+
   /* Is the process' root directory on the same partition?,
    * if so, set the chroot directory too. */
   if (rfp->fp_rd->v_dev == rfp->fp_wd->v_dev)
@@ -500,6 +507,7 @@ struct fproc *rfp;
        /* Unlock a previously locked vmnt if locked and lock new vmnt */
        if (vmpres) unlock_vmnt(vmpres);
        vmpres = find_vmnt(fs_e);
+       if (vmpres == NULL) return(EIO);        /* mount point vanished? */
        if ((r = lock_vmnt(vmpres, resolve->l_vmnt_lock)) != OK) {
                if (r == EBUSY)
                        vmpres = NULL;  /* Already locked */
index 54d4a9d0c8ec4681daae0760b6d96fcb5d65db73..e0a815293e80550773746ddd250d46729b64c8e8 100644 (file)
@@ -21,6 +21,7 @@ struct job;
 typedef struct filp * filp_id_t;
 
 /* comm.c */
+_PROTOTYPE(void fs_cancel, (struct vmnt *vmp)                          );
 _PROTOTYPE(int fs_sendrec, (endpoint_t fs_e, message *reqm)            );
 _PROTOTYPE(void fs_sendmore, (struct vmnt *vmp)                                );
 _PROTOTYPE(void send_work, (void)                                      );
@@ -92,7 +93,8 @@ _PROTOTYPE( struct filp *get_filp2, (struct fproc *rfp, int fild,
 _PROTOTYPE( void lock_filp, (struct filp *filp, tll_access_t locktype) );
 _PROTOTYPE( void unlock_filp, (struct filp *filp)                      );
 _PROTOTYPE( void unlock_filps, (struct filp *filp1, struct filp *filp2)        );
-_PROTOTYPE( int invalidate, (struct filp *)                            );
+_PROTOTYPE( int invalidate_filp, (struct filp *)                       );
+_PROTOTYPE( void invalidate_filp_by_endpt, (endpoint_t proc_e)         );
 _PROTOTYPE( int do_verify_fd, (void)                                   );
 _PROTOTYPE( int set_filp, (filp_id_t sfilp)                            );
 _PROTOTYPE( int do_set_filp, (void)                                    );
@@ -334,6 +336,7 @@ _PROTOTYPE( struct vmnt *get_locked_vmnt, (struct fproc *rfp)               );
 _PROTOTYPE( void init_vmnts, (void)                                    );
 _PROTOTYPE( int lock_vmnt, (struct vmnt *vp, tll_access_t locktype)    );
 _PROTOTYPE( void unlock_vmnt, (struct vmnt *vp)                                );
+_PROTOTYPE( void vmnt_unmap_by_endpt, (endpoint_t proc_e)              );
 
 /* vnode.c */
 _PROTOTYPE( void check_vnode_locks, (void)                             );
index 66c40567831699f489778644fb1885fc4429c86b..a762421f33b2b72413cebc286e424a1491758b8e 100644 (file)
@@ -159,6 +159,21 @@ PUBLIC int lock_vmnt(struct vmnt *vmp, tll_access_t locktype)
   return(OK);
 }
 
+/*===========================================================================*
+ *                             vmnt_unmap_by_endpoint                       *
+ *===========================================================================*/
+PUBLIC void vmnt_unmap_by_endpt(endpoint_t proc_e)
+{
+  struct vmnt *vmp;
+
+  if ((vmp = find_vmnt(proc_e)) != NULL) {
+       fs_cancel(vmp);
+       invalidate_filp_by_endpt(proc_e);
+       put_vnode(vmp->m_mounted_on);
+       clear_vmnt(vmp);
+  }
+}
+
 /*===========================================================================*
  *                             unlock_vmnt                                  *
  *===========================================================================*/