From: Ben Gras Date: Wed, 29 Apr 2009 16:59:18 +0000 (+0000) Subject: cleanup of vfs shutdown logic; makes clean unmounts easier (but X-Git-Tag: v3.1.4~62 X-Git-Url: http://zhaoyanbai.com/repos/dig.html?a=commitdiff_plain;h=fd7ef243e48ca964feea04dec7c6730e1ad95974;p=minix.git cleanup of vfs shutdown logic; makes clean unmounts easier (but needs checking if fp_wd or fp_rd is NULL before use) --- diff --git a/servers/vfs/fproc.h b/servers/vfs/fproc.h index 961af0014..d1052cd93 100644 --- a/servers/vfs/fproc.h +++ b/servers/vfs/fproc.h @@ -10,8 +10,8 @@ EXTERN struct fproc { mode_t fp_umask; /* mask set by umask system call */ - struct vnode *fp_wd; /* working directory */ - struct vnode *fp_rd; /* root directory */ + struct vnode *fp_wd; /* working directory; NULL during reboot */ + struct vnode *fp_rd; /* root directory; NULL during reboot */ struct filp *fp_filp[OPEN_MAX];/* the file descriptor table */ diff --git a/servers/vfs/main.c b/servers/vfs/main.c index f28b49788..024f4e92a 100644 --- a/servers/vfs/main.c +++ b/servers/vfs/main.c @@ -104,12 +104,12 @@ PUBLIC int main() /* Check for special control messages first. */ if ((call_nr & NOTIFY_MESSAGE)) { - if (call_nr == PROC_EVENT) + if (call_nr == PROC_EVENT && who_e == PM_PROC_NR) { /* PM tries to get FS to do something */ service_pm(); } - else if (call_nr == SYN_ALARM) + else if (call_nr == SYN_ALARM && who_e == CLOCK) { /* Alarm timer expired. Used only for select(). * Check it. diff --git a/servers/vfs/misc.c b/servers/vfs/misc.c index 2f391a8f0..54f54d8e3 100644 --- a/servers/vfs/misc.c +++ b/servers/vfs/misc.c @@ -298,6 +298,33 @@ PUBLIC int do_fsync() return(OK); } +void unmount_all(void) +{ + int i; + int found = 0, worked = 0, remain = 0; + /* Unmount all filesystems. File systems are mounted on other file systems, + * so you have to pull off the loose bits repeatedly to get it all undone. + */ + for (i= 0; i < NR_SUPERS; i++) { + struct vmnt *vmp; + /* Unmount at least one. */ + worked = remain = 0; + for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; vmp++) { + if (vmp->m_dev != NO_DEV) { + found++; + CHECK_VREFS; + if(unmount(vmp->m_dev) == OK) + worked++; + else + remain++; + CHECK_VREFS; + } + } + } + + printf("VFS: worked: %d remain: %d\n", worked, remain); +} + /*===========================================================================* * pm_reboot * *===========================================================================*/ @@ -305,7 +332,6 @@ PUBLIC void pm_reboot() { /* Perform the FS side of the reboot call. */ int i; - struct vmnt *vmp; do_sync(); @@ -316,27 +342,17 @@ PUBLIC void pm_reboot() * will tell us about it). */ for (i = 0; i < NR_PROCS; i++) - if((m_in.endpt1 = fproc[i].fp_endpoint) != NONE) - free_proc(&fproc[i], FP_EXITING); + if((m_in.endpt1 = fproc[i].fp_endpoint) != NONE) { + /* No FP_EXITING, just free the resources, otherwise + * consistency check for fp_endpoint (set to NONE) will + * fail if process wants to do something in the (short) + * future. + */ + free_proc(&fproc[i], 0); + } CHECK_VREFS; - /* The root file system is mounted onto itself, which keeps it from being - * unmounted. Pull an inode out of thin air and put the root on it. - */ - - /* Unmount all filesystems. File systems are mounted on other file systems, - * so you have to pull off the loose bits repeatedly to get it all undone. - */ - for (i= 0; i < NR_SUPERS; i++) { - /* Unmount at least one. */ - for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; vmp++) { - if (vmp->m_dev != NO_DEV) { - CHECK_VREFS; - (void) unmount(vmp->m_dev); - CHECK_VREFS; - } - } - } + unmount_all(); CHECK_VREFS; @@ -378,6 +394,7 @@ int cpid; /* Child process id */ /* Increase the counters in the 'filp' table. */ cp = &fproc[childno]; fp = &fproc[parentno]; + for (i = 0; i < OPEN_MAX; i++) if (cp->fp_filp[i] != NIL_FILP) cp->fp_filp[i]->filp_count++; @@ -404,8 +421,8 @@ int cpid; /* Child process id */ cp->fp_execced = 0; /* Record the fact that both root and working dir have another user. */ - dup_vnode(cp->fp_rd); - dup_vnode(cp->fp_wd); + if(cp->fp_rd) dup_vnode(cp->fp_rd); + if(cp->fp_wd) dup_vnode(cp->fp_wd); } /*===========================================================================* @@ -421,6 +438,10 @@ PRIVATE void free_proc(struct fproc *exiter, int flags) fp = exiter; /* get_filp() needs 'fp' */ + if(fp->fp_endpoint == NONE) { + panic(__FILE__, "free_proc: already free", NO_NUM); + } + if (fp->fp_suspended == SUSPENDED) { task = -fp->fp_task; if (task == XPIPE || task == XPOPEN) susp_count--; @@ -432,12 +453,6 @@ PRIVATE void free_proc(struct fproc *exiter, int flags) for (i = 0; i < OPEN_MAX; i++) { (void) close_fd(fp, i); } - - /* Release root and working directories. */ - put_vnode(fp->fp_rd); - put_vnode(fp->fp_wd); - fp->fp_rd = NIL_VNODE; - fp->fp_wd = NIL_VNODE; /* Check if any process is SUSPENDed on this driver. * If a driver exits, unmap its entries in the dmap table. @@ -446,6 +461,12 @@ PRIVATE void free_proc(struct fproc *exiter, int flags) */ unsuspend_by_endpt(fp->fp_endpoint); + /* Release root and working directories. */ + if(fp->fp_rd) { put_vnode(fp->fp_rd); fp->fp_rd = NIL_VNODE; } + if(fp->fp_wd) { put_vnode(fp->fp_wd); fp->fp_wd = NIL_VNODE; } + + CHECK_VREFS; + /* The rest of these actions is only done when processes actually * exit. */ diff --git a/servers/vfs/mount.c b/servers/vfs/mount.c index 8fd1cbbd4..871c67266 100644 --- a/servers/vfs/mount.c +++ b/servers/vfs/mount.c @@ -327,18 +327,14 @@ PRIVATE int mount_fs(endpoint_t fs_e) if (tfp->fp_pid == PID_FREE) continue; - if (tfp->fp_rd == NULL) - panic("fs", "do_mount: null rootdir", i); - if (tfp->fp_wd == NULL) - panic("fs", "do_mount: null workdir", i); - - put_vnode(tfp->fp_rd); - dup_vnode(root_node); - tfp->fp_rd = root_node; - - put_vnode(tfp->fp_wd); - dup_vnode(root_node); - tfp->fp_wd = root_node; +#define MAKEROOT(what) { \ + put_vnode(what); \ + dup_vnode(root_node); \ + what = root_node; \ + } + + if(tfp->fp_rd) MAKEROOT(tfp->fp_rd); + if(tfp->fp_wd) MAKEROOT(tfp->fp_wd); } CHECK_VREFS; @@ -435,13 +431,11 @@ Dev_t dev; for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; vp++) { if (vp->v_ref_count > 0 && vp->v_dev == dev) { -#if 1 +#if 0 int i; struct fproc *tfp; - if(!(vp->v_inode_nr == 1 && vp->v_ref_count == 1)) { printf("unmount: vnode 0x%x/%d in use %d times\n", dev, vp->v_inode_nr, vp->v_ref_count); - } for (i= 0, tfp= fproc; ifp_pid == PID_FREE) @@ -465,7 +459,7 @@ Dev_t dev; printf("\tvnode %d: is a mount point\n", vp->v_inode_nr); } -#if 0 +#if 1 if(vmp_i->m_root_node == vp) { printf("\tvnode %d: is a root node\n", vp->v_inode_nr); diff --git a/servers/vfs/open.c b/servers/vfs/open.c index 4050f89a3..7af05c83f 100644 --- a/servers/vfs/open.c +++ b/servers/vfs/open.c @@ -251,6 +251,11 @@ int *created; struct node_details res; char lastc[PATH_MAX+1]; + if(!fp->fp_rd || !fp->fp_wd) { + printf("VFS: %d: no rd/wd\n", fp->fp_endpoint); + return ENOENT; + } + start_vp = (user_fullpath[0] == '/' ? fp->fp_rd : fp->fp_wd); dup_vnode(start_vp); diff --git a/servers/vfs/path.c b/servers/vfs/path.c index 6828b7871..dc3006afb 100644 --- a/servers/vfs/path.c +++ b/servers/vfs/path.c @@ -109,6 +109,11 @@ struct vnode **vpp; */ struct vnode *vp; + if(!fp->fp_rd || !fp->fp_wd) { + printf("VFS: lookup_vp %d: no rd/wd\n", fp->fp_endpoint); + return ENOENT; + } + vp= (user_fullpath[0] == '/' ? fp->fp_rd : fp->fp_wd); return lookup_rel_vp(vp, flags, use_realuid, vpp); @@ -207,6 +212,11 @@ struct vnode **vpp; */ struct vnode *vp; + if(!fp->fp_rd || !fp->fp_wd) { + printf("VFS: lookup_lastdir %d: no rd/wd\n", fp->fp_endpoint); + return ENOENT; + } + vp= (user_fullpath[0] == '/' ? fp->fp_rd : fp->fp_wd); return lookup_lastdir_rel(vp, use_realuid, vpp); } @@ -239,6 +249,11 @@ node_details_t *node; return ENOENT; } + if(!fp->fp_rd || !fp->fp_wd) { + printf("VFS: lookup_rel %d: no rd/wd\n", fp->fp_endpoint); + return ENOENT; + } + fs_e = start_node->v_fs_e; path_off = 0; dir_ino = start_node->v_inode_nr; diff --git a/servers/vfs/stadir.c b/servers/vfs/stadir.c index 975f4a333..d894900af 100644 --- a/servers/vfs/stadir.c +++ b/servers/vfs/stadir.c @@ -39,6 +39,12 @@ PUBLIC int do_fchdir() struct filp *rfilp; int r; + if(!fp->fp_wd || !fp->fp_rd) { + printf("VFS: do_fchdir: %d: no rd/wd\n", + fp->fp_endpoint); + return ENOENT; + } + /* Is the file descriptor valid? */ if ( (rfilp = get_filp(m_in.fd)) == NIL_FILP) return(err_code); @@ -67,11 +73,22 @@ PUBLIC int do_chdir() int r; register struct fproc *rfp; + if(!fp->fp_wd || !fp->fp_rd) { + printf("VFS: do_chdir: %d: no rd/wd\n", + fp->fp_endpoint); + return ENOENT; + } + if (who_e == PM_PROC_NR) { int slot; if(isokendpt(m_in.endpt1, &slot) != OK) return EINVAL; rfp = &fproc[slot]; + + if(!rfp->fp_wd || !rfp->fp_rd) { + printf("VFS: do_chdir: %d: no other rd/wd\n", fp->fp_endpoint); + return ENOENT; + } put_vnode(fp->fp_rd); dup_vnode(fp->fp_rd = rfp->fp_rd); @@ -106,6 +123,12 @@ PUBLIC int do_chroot() register int r; if (!super_user) return(EPERM); /* only su may chroot() */ + + if(!fp->fp_wd || !fp->fp_rd) { + printf("VFS: do_chroot: %d: no rd/wd\n", + fp->fp_endpoint); + return ENOENT; + } r = change(&fp->fp_rd, m_in.name, m_in.name_length); return(r); diff --git a/servers/vfs/vnode.c b/servers/vfs/vnode.c index 7d28a0502..286f3689a 100644 --- a/servers/vfs/vnode.c +++ b/servers/vfs/vnode.c @@ -189,8 +189,8 @@ PUBLIC int check_vrefs() for (rfp=&fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { if (rfp->fp_pid == PID_FREE) continue; - REFVP(rfp->fp_rd); - REFVP(rfp->fp_wd); + if(rfp->fp_rd) REFVP(rfp->fp_rd); + if(rfp->fp_wd) REFVP(rfp->fp_wd); } /* Count references from filedescriptors */