From: Thomas Veerman Date: Thu, 19 Jan 2012 14:21:46 +0000 (+0000) Subject: Add support for survival of crashed FSs X-Git-Tag: v3.2.0~113 X-Git-Url: http://zhaoyanbai.com/repos/icons/jhe061.png?a=commitdiff_plain;h=ddbdca6cdb0d33fc6d254a75b424466e32f9d091;p=minix.git Add support for survival of crashed FSs 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. --- diff --git a/servers/avfs/comm.c b/servers/avfs/comm.c index 85b6d2f49..89b2e503c 100644 --- a/servers/avfs/comm.c +++ b/servers/avfs/comm.c @@ -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) { diff --git a/servers/avfs/device.c b/servers/avfs/device.c index 29130df29..969ac8b7d 100644 --- a/servers/avfs/device.c +++ b/servers/avfs/device.c @@ -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); diff --git a/servers/avfs/filedes.c b/servers/avfs/filedes.c index 83a432c1b..681030623 100644 --- a/servers/avfs/filedes.c +++ b/servers/avfs/filedes.c @@ -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 * *===========================================================================*/ diff --git a/servers/avfs/misc.c b/servers/avfs/misc.c index 31a8af2b8..ed866016b 100644 --- a/servers/avfs/misc.c +++ b/servers/avfs/misc.c @@ -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; diff --git a/servers/avfs/path.c b/servers/avfs/path.c index 2ac2eece0..d33f711a8 100644 --- a/servers/avfs/path.c +++ b/servers/avfs/path.c @@ -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 */ diff --git a/servers/avfs/proto.h b/servers/avfs/proto.h index 54d4a9d0c..e0a815293 100644 --- a/servers/avfs/proto.h +++ b/servers/avfs/proto.h @@ -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) ); diff --git a/servers/avfs/vmnt.c b/servers/avfs/vmnt.c index 66c405678..a762421f3 100644 --- a/servers/avfs/vmnt.c +++ b/servers/avfs/vmnt.c @@ -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 * *===========================================================================*/