#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>
* 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++) {
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;
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 *
* 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;
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) {
/* 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) {
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;
/* 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);
}
/* 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) {