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
This commit is contained in:
parent
14e641cb8c
commit
28f2a169da
@ -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;
|
||||
|
@ -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. */
|
||||
|
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user