]> Zhao Yanbai Git Server - minix.git/commitdiff
VFS: bugfixes for handling block-special files:
authorDavid van Moolenbroek <david@minix3.org>
Fri, 25 Mar 2011 10:56:43 +0000 (10:56 +0000)
committerDavid van Moolenbroek <david@minix3.org>
Fri, 25 Mar 2011 10:56:43 +0000 (10:56 +0000)
- 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

servers/vfs/device.c
servers/vfs/main.c
servers/vfs/mount.c

index c304c30b73281771e50819f661e806255e0f91d0..3ca5d3c19f33a5fc68247f1dea859791cec46802 100644 (file)
@@ -20,6 +20,7 @@
 #include "fs.h"
 #include <fcntl.h>
 #include <assert.h>
+#include <sys/stat.h>
 #include <minix/callnr.h>
 #include <minix/com.h>
 #include <minix/endpoint.h>
@@ -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;
index d514863244eb226104b9d9c79c8e5e93f895ec62..6317886c0cfc3a8707dcdea35be170c520b3e246 100644 (file)
@@ -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. */
index 1bdbb5e26a73d74cb5c7f862c9473e9f82b43a96..42f1c202c7259b5b7ba937ff84c01c0df49a3051 100644 (file)
@@ -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) {