From: David van Moolenbroek Date: Fri, 25 Mar 2011 10:56:43 +0000 (+0000) Subject: VFS: bugfixes for handling block-special files: X-Git-Tag: v3.2.0~600 X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/icons/FAQ?a=commitdiff_plain;h=28f2a169da68d5d97b3d1e92ef1c0e2c67360e83;p=minix.git VFS: bugfixes for handling block-special files: - on driver restarts, reopen devices on a per-file basis, not per-mount - do not assume that there is just one vnode per block-special device - update block-special files in the uncommon mounting success paths, too - upon mount, sync but also invalidate affected buffers on the root FS - upon unmount, check whether a vnode is in use before updating it --- diff --git a/servers/vfs/device.c b/servers/vfs/device.c index c304c30b7..3ca5d3c19 100644 --- a/servers/vfs/device.c +++ b/servers/vfs/device.c @@ -20,6 +20,7 @@ #include "fs.h" #include #include +#include #include #include #include @@ -851,36 +852,59 @@ PUBLIC void dev_up(int maj) * checks if any filesystems are mounted on it, and if so, * dev_open()s them so the filesystem can be reused. */ - int r, new_driver_e, needs_reopen, fd_nr; + int r, new_driver_e, needs_reopen, fd_nr, found; struct filp *fp; struct vmnt *vmp; struct fproc *rfp; struct vnode *vp; - /* Open a device once for every filp that's opened on it, - * and once for every filesystem mounted from it. + /* First deal with block devices. We need to consider both mounted file + * systems and open block-special files. */ new_driver_e = dmap[maj].dmap_driver; + /* Tell each affected mounted file system about the new endpoint. This code + * is currently useless, as driver endpoints do not change across restarts. + */ for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp) { - int minor; - if (vmp->m_dev == NO_DEV) continue; - if ( ((vmp->m_dev >> MAJOR) & BYTE) != maj) continue; - minor = ((vmp->m_dev >> MINOR) & BYTE); + if (major(vmp->m_dev) != maj) continue; - if ((r = dev_open(vmp->m_dev, VFS_PROC_NR, - vmp->m_flags ? R_BIT : (R_BIT|W_BIT))) != OK) { - printf("VFS: mounted dev %d/%d re-open failed: %d.\n", - maj, minor, r); - } - - /* Send new driver endpoint */ + /* Send the new driver endpoint to the mounted file system. */ if (OK != req_newdriver(vmp->m_fs_e, vmp->m_dev, new_driver_e)) printf("VFSdev_up: error sending new driver endpoint." " FS_e: %d req_nr: %d\n", vmp->m_fs_e, REQ_NEW_DRIVER); } - /* Look for processes that are suspened in an OPEN call. Set SUSP_REOPEN + /* For each block-special file that was previously opened on the affected + * device, we need to reopen it on the new driver. + */ + found = 0; + for (fp = filp; fp < &filp[NR_FILPS]; fp++) { + if(fp->filp_count < 1 || !(vp = fp->filp_vno)) continue; + if(major(vp->v_sdev) != maj) continue; + if(!S_ISBLK(vp->v_mode)) continue; + + /* Reopen the device on the driver, once per filp. */ + if ((r = dev_open(vp->v_sdev, VFS_PROC_NR, fp->filp_mode)) != OK) + printf("VFS: mounted dev %d/%d re-open failed: %d.\n", + maj, minor(vp->v_sdev), r); + + found = 1; + } + + /* If any block-special file was open for this major at all, also inform the + * root file system about the new endpoint of the driver. We do this even if + * the block-special file is linked to another mounted file system, merely + * because it is more work to check for that case. + */ + if (found) { + if (OK != req_newdriver(ROOT_FS_E, makedev(maj, 0), new_driver_e)) + printf("VFSdev_up: error sending new driver endpoint." + " FS_e: %d req_nr: %d\n", ROOT_FS_E, REQ_NEW_DRIVER); + } + + /* The rest of the code deals with character-special files. To start with, + * look for processes that are suspened in an OPEN call. Set SUSP_REOPEN * to indicate that this process was suspended before the call to dev_up. */ for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { @@ -901,11 +925,9 @@ PUBLIC void dev_up(int maj) needs_reopen= FALSE; for (fp = filp; fp < &filp[NR_FILPS]; fp++) { - struct vnode *vp; - if(fp->filp_count < 1 || !(vp = fp->filp_vno)) continue; if(((vp->v_sdev >> MAJOR) & BYTE) != maj) continue; - if(!(vp->v_mode & (I_BLOCK_SPECIAL|I_CHAR_SPECIAL))) continue; + if(!S_ISCHR(vp->v_mode)) continue; fp->filp_state = FS_NEEDS_REOPEN; needs_reopen = TRUE; diff --git a/servers/vfs/main.c b/servers/vfs/main.c index d51486324..6317886c0 100644 --- a/servers/vfs/main.c +++ b/servers/vfs/main.c @@ -440,7 +440,6 @@ PRIVATE void init_root() struct vnode *root_node; struct dmap *dp; char *label; - message m; struct node_details res; /* Open the root device. */ diff --git a/servers/vfs/mount.c b/servers/vfs/mount.c index 1bdbb5e26..42f1c202c 100644 --- a/servers/vfs/mount.c +++ b/servers/vfs/mount.c @@ -41,7 +41,23 @@ PRIVATE bitchunk_t nonedev[BITMAP_CHUNKS(NR_NONEDEVS)] = { 0 }; FORWARD _PROTOTYPE( dev_t name_to_dev, (int allow_mountpt) ); FORWARD _PROTOTYPE( int mount_fs, (endpoint_t fs_e) ); FORWARD _PROTOTYPE( int is_nonedev, (dev_t dev) ); -FORWARD _PROTOTYPE( dev_t find_free_nonedev, (void) ); +FORWARD _PROTOTYPE( dev_t find_free_nonedev, (void) ); + +/*===========================================================================* + * update_bspec * + *===========================================================================*/ +PRIVATE void update_bspec(dev_t dev, endpoint_t fs_e) +{ +/* Update all block special files for a certain device, to use a new FS endpt + * to route raw block I/O requests through. + */ + struct vnode *vp; + + for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; ++vp) + if (vp->v_ref_count > 0 && S_ISBLK(vp->v_mode) && vp->v_sdev == dev) + vp->v_bfs_e = fs_e; +} + /*===========================================================================* * do_fslogin * @@ -136,19 +152,11 @@ PRIVATE int mount_fs(endpoint_t fs_e) * same device (partition) */ for (bspec = &vnode[0]; bspec < &vnode[NR_VNODES]; ++bspec) { if (bspec->v_ref_count > 0 && bspec->v_sdev == dev) { - /* Found, sync the buffer cache */ - req_sync(bspec->v_fs_e); + /* Found, flush and invalidate any blocks for this device. */ + req_flush(bspec->v_fs_e, dev); break; - /* Note: there are probably some blocks in the FS process' - * buffer cache which contain data on this minor, although - * they will be purged since the handling moves to the new - * FS process (if everything goes well with the mount...) - */ } } - /* Didn't find? */ - if (bspec == &vnode[NR_VNODES] && bspec->v_sdev != dev) - bspec = NULL; /* Scan vmnt table to see if dev already mounted. If not, find a free slot.*/ found = FALSE; @@ -202,6 +210,7 @@ PRIVATE int mount_fs(endpoint_t fs_e) strcpy(vmp->m_label, mount_label); allow_newroot = 0; /* The root is now fixed */ if (nodev) alloc_nonedev(dev); /* Make the allocation final */ + update_bspec(dev, fs_e); /* Update open block-special files */ return(OK); } else if (vmp == NULL) { @@ -218,11 +227,10 @@ PRIVATE int mount_fs(endpoint_t fs_e) /* Get vnode of mountpoint */ if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); - if (vp->v_ref_count != 1) { - put_vnode(vp); - return(EBUSY); - } - + if (vp->v_ref_count != 1) { + put_vnode(vp); + return(EBUSY); + } /* Tell FS on which vnode it is mounted (glue into mount tree) */ if ((r = req_mountpoint(vp->v_fs_e, vp->v_inode_nr)) != OK) { @@ -285,6 +293,7 @@ PRIVATE int mount_fs(endpoint_t fs_e) vmp->m_mounted_on = NULL; strcpy(vmp->m_label, mount_label); if (nodev) alloc_nonedev(dev); + update_bspec(dev, fs_e); root_dev = dev; ROOT_FS_E = fs_e; @@ -331,9 +340,8 @@ PRIVATE int mount_fs(endpoint_t fs_e) /* Allocate the pseudo device that was found, if not using a real device. */ if (nodev) alloc_nonedev(dev); - /* There was a block spec file open, and it should be handled by the - * new FS proc now */ - if (bspec) bspec->v_bfs_e = fs_e; + /* The new FS will handle block I/O requests for its device now. */ + update_bspec(dev, fs_e); return(OK); } @@ -431,8 +439,9 @@ PUBLIC int unmount( /* Is there a block special file that was handled by that partition? */ for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; vp++) { - if((vp->v_mode & I_TYPE)==I_BLOCK_SPECIAL && vp->v_bfs_e==vmp->m_fs_e){ - + if(vp->v_ref_count > 0 && S_ISBLK(vp->v_mode) && + vp->v_bfs_e == vmp->m_fs_e) { + /* Get the driver endpoint of the block spec device */ dp = &dmap[(dev >> MAJOR) & BYTE]; if (dp->dmap_driver == NONE) {