Fix locking issues with back calls from FSes
This commit is contained in:
parent
195190912f
commit
ae2159c371
10 changed files with 79 additions and 48 deletions
|
@ -385,6 +385,10 @@ PRIVATE void *do_work(void *arg)
|
|||
|
||||
lock_proc(fp, 0); /* This proc is busy */
|
||||
|
||||
if (verbose) {
|
||||
printf("Doing call_nr = %d for %d\n", call_nr, who_e);
|
||||
}
|
||||
|
||||
if (call_nr == MAPDRIVER) {
|
||||
error = do_mapdriver();
|
||||
} else if (call_nr == COMMON_GETSYSINFO) {
|
||||
|
|
|
@ -284,14 +284,19 @@ PUBLIC int do_fcntl()
|
|||
PUBLIC int do_sync()
|
||||
{
|
||||
struct vmnt *vmp;
|
||||
int r = OK;
|
||||
|
||||
for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp) {
|
||||
lock_vmnt(vmp, VMNT_EXCL);
|
||||
if (vmp->m_dev != NO_DEV && vmp->m_fs_e != NONE)
|
||||
if (vmp->m_dev != NO_DEV && vmp->m_fs_e != NONE &&
|
||||
vmp->m_root_node != NULL) {
|
||||
if ((r = lock_vmnt(vmp, VMNT_EXCL)) != OK)
|
||||
break;
|
||||
req_sync(vmp->m_fs_e);
|
||||
unlock_vmnt(vmp);
|
||||
}
|
||||
}
|
||||
|
||||
return(OK);
|
||||
return(r);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
@ -299,23 +304,28 @@ PUBLIC int do_sync()
|
|||
*===========================================================================*/
|
||||
PUBLIC int do_fsync()
|
||||
{
|
||||
/* Perform the fsync() system call. For now, don't be unnecessarily smart. */
|
||||
/* Perform the fsync() system call. */
|
||||
struct filp *rfilp;
|
||||
struct vmnt *vmp;
|
||||
dev_t dev;
|
||||
int r = OK;
|
||||
|
||||
if ((rfilp = get_filp(m_in.m1_i1, VNODE_READ)) == NULL) return(err_code);
|
||||
dev = rfilp->filp_vno->v_dev;
|
||||
for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp) {
|
||||
lock_vmnt(vmp, VMNT_EXCL);
|
||||
if (vmp->m_dev != NO_DEV && vmp->m_dev == dev && vmp->m_fs_e != NONE)
|
||||
if (vmp->m_dev != NO_DEV && vmp->m_dev == dev &&
|
||||
vmp->m_fs_e != NONE && vmp->m_root_node != NULL) {
|
||||
|
||||
if ((r = lock_vmnt(vmp, VMNT_EXCL)) != OK)
|
||||
break;
|
||||
req_sync(vmp->m_fs_e);
|
||||
unlock_vmnt(vmp);
|
||||
}
|
||||
}
|
||||
|
||||
unlock_filp(rfilp);
|
||||
|
||||
return(OK);
|
||||
return(r);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
@ -344,6 +354,7 @@ PUBLIC void pm_reboot()
|
|||
}
|
||||
}
|
||||
|
||||
do_sync();
|
||||
unmount_all();
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,6 @@ PRIVATE bitchunk_t nonedev[BITMAP_CHUNKS(NR_NONEDEVS)] = { 0 };
|
|||
|
||||
FORWARD _PROTOTYPE( dev_t name_to_dev, (int allow_mountpt,
|
||||
char path[PATH_MAX+1]) );
|
||||
FORWARD _PROTOTYPE( int is_nonedev, (dev_t dev) );
|
||||
FORWARD _PROTOTYPE( dev_t find_free_nonedev, (void) );
|
||||
FORWARD _PROTOTYPE( void update_bspec, (dev_t dev, endpoint_t fs_e,
|
||||
int send_drv_e) );
|
||||
|
@ -153,7 +152,8 @@ PUBLIC int do_mount()
|
|||
return(err_code);
|
||||
|
||||
/* Do the actual job */
|
||||
return mount_fs(dev, fullpath, fs_e, rdonly, mount_label);
|
||||
r = mount_fs(dev, fullpath, fs_e, rdonly, mount_label);
|
||||
return(r);
|
||||
}
|
||||
|
||||
|
||||
|
@ -191,32 +191,18 @@ char mount_label[LABEL_MAX] )
|
|||
assert(strlen(label) > 0);
|
||||
}
|
||||
|
||||
lock_bsf();
|
||||
|
||||
/* Check whether there is a block special file open which uses the
|
||||
* same device (partition) */
|
||||
for (bspec = &vnode[0]; bspec < &vnode[NR_VNODES]; ++bspec) {
|
||||
if (bspec->v_ref_count > 0 && bspec->v_sdev == dev) {
|
||||
/* Found, flush and invalidate any blocks for this device. */
|
||||
req_flush(bspec->v_fs_e, dev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Scan vmnt table to see if dev already mounted. If not, find a free slot.*/
|
||||
found = FALSE;
|
||||
for (i = 0; i < NR_MNTS; ++i) {
|
||||
if (vmnt[i].m_dev == dev) found = TRUE;
|
||||
}
|
||||
if (found) {
|
||||
unlock_bsf();
|
||||
return(EBUSY);
|
||||
} else if ((new_vmp = get_free_vmnt()) == NULL) {
|
||||
unlock_bsf();
|
||||
return(ENOMEM);
|
||||
}
|
||||
|
||||
lock_vmnt(new_vmp, VMNT_EXCL);
|
||||
if ((r = lock_vmnt(new_vmp, VMNT_EXCL)) != OK) return(r);
|
||||
|
||||
isroot = (strcmp(mountpoint, "/") == 0);
|
||||
mount_root = (isroot && have_root < 2); /* Root can be mounted twice:
|
||||
|
@ -237,14 +223,15 @@ char mount_label[LABEL_MAX] )
|
|||
} else
|
||||
r = EBUSY;
|
||||
|
||||
if (vp != NULL)
|
||||
unlock_vmnt(parent_vmp);
|
||||
|
||||
if (r != OK) {
|
||||
if (vp != NULL) {
|
||||
unlock_vnode(vp);
|
||||
unlock_vmnt(parent_vmp);
|
||||
put_vnode(vp);
|
||||
}
|
||||
unlock_vmnt(new_vmp);
|
||||
unlock_bsf();
|
||||
return(r);
|
||||
}
|
||||
}
|
||||
|
@ -254,11 +241,9 @@ char mount_label[LABEL_MAX] )
|
|||
if ((root_node = get_free_vnode()) == NULL || dev == 266) {
|
||||
if (vp != NULL) {
|
||||
unlock_vnode(vp);
|
||||
unlock_vmnt(parent_vmp);
|
||||
put_vnode(vp);
|
||||
}
|
||||
unlock_vmnt(new_vmp);
|
||||
unlock_bsf();
|
||||
return(err_code);
|
||||
}
|
||||
|
||||
|
@ -271,19 +256,21 @@ char mount_label[LABEL_MAX] )
|
|||
else new_vmp->m_flags &= ~VMNT_READONLY;
|
||||
|
||||
/* Tell FS which device to mount */
|
||||
if (verbose)
|
||||
printf("Tell FS %d to mount device %s %d\n", fs_e, label, dev);
|
||||
if ((r = req_readsuper(fs_e, label, dev, rdonly, isroot, &res)) != OK) {
|
||||
if (verbose) printf("Failed: %d\n", r);
|
||||
if (vp != NULL) {
|
||||
unlock_vnode(vp);
|
||||
unlock_vmnt(parent_vmp);
|
||||
put_vnode(vp);
|
||||
}
|
||||
new_vmp->m_fs_e = NONE;
|
||||
new_vmp->m_dev = NO_DEV;
|
||||
unlock_vnode(root_node);
|
||||
unlock_vmnt(new_vmp);
|
||||
unlock_bsf();
|
||||
return(r);
|
||||
}
|
||||
if (verbose) printf("Ok done: r=%d\n", r);
|
||||
|
||||
/* Fill in root node's fields */
|
||||
root_node->v_fs_e = res.fs_e;
|
||||
|
@ -300,6 +287,8 @@ char mount_label[LABEL_MAX] )
|
|||
root_node->v_vmnt = new_vmp;
|
||||
root_node->v_dev = new_vmp->m_dev;
|
||||
|
||||
lock_bsf();
|
||||
|
||||
if (mount_root) {
|
||||
/* Superblock and root node already read.
|
||||
* Nothing else can go wrong. Perform the mount. */
|
||||
|
@ -342,7 +331,6 @@ char mount_label[LABEL_MAX] )
|
|||
/* If error, return the super block and both inodes; release the vmnt. */
|
||||
if (r != OK) {
|
||||
unlock_vnode(vp);
|
||||
unlock_vmnt(parent_vmp);
|
||||
unlock_vnode(root_node);
|
||||
unlock_vmnt(new_vmp);
|
||||
put_vnode(vp);
|
||||
|
@ -364,7 +352,6 @@ char mount_label[LABEL_MAX] )
|
|||
update_bspec(dev, fs_e, 0 /* Don't send new driver endpoint */);
|
||||
|
||||
unlock_vnode(vp);
|
||||
unlock_vmnt(parent_vmp);
|
||||
unlock_vnode(root_node);
|
||||
unlock_vmnt(new_vmp);
|
||||
unlock_bsf();
|
||||
|
@ -454,7 +441,10 @@ PUBLIC int unmount(
|
|||
|
||||
lock_bsf();
|
||||
|
||||
assert(lock_vmnt(vmp, VMNT_EXCL) == OK);
|
||||
if ((r = lock_vmnt(vmp, VMNT_EXCL)) != OK) {
|
||||
unlock_bsf();
|
||||
return(r);
|
||||
}
|
||||
|
||||
/* See if the mounted device is busy. Only 1 vnode using it should be
|
||||
* open -- the root vnode -- and that inode only 1 time. */
|
||||
|
@ -577,7 +567,7 @@ PRIVATE dev_t name_to_dev(int allow_mountpt, char path[PATH_MAX+1])
|
|||
/*===========================================================================*
|
||||
* is_nonedev *
|
||||
*===========================================================================*/
|
||||
PRIVATE int is_nonedev(dev_t dev)
|
||||
PUBLIC int is_nonedev(dev_t dev)
|
||||
{
|
||||
/* Return whether the given device is a "none" pseudo device.
|
||||
*/
|
||||
|
|
|
@ -180,7 +180,8 @@ PRIVATE int common_open(char path[PATH_MAX+1], int oflags, mode_t omode)
|
|||
* we default to ROOT_FS. */
|
||||
vp->v_bfs_e = ROOT_FS_E; /* By default */
|
||||
for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp)
|
||||
if (vmp->m_dev == vp->v_sdev)
|
||||
if (vmp->m_dev == vp->v_sdev &&
|
||||
!is_nonedev(vmp->m_dev))
|
||||
vp->v_bfs_e = vmp->m_fs_e;
|
||||
|
||||
/* Get the driver endpoint of the block spec device */
|
||||
|
|
|
@ -169,6 +169,10 @@ struct fproc *rfp;
|
|||
char *cp;
|
||||
char dir_entry[PATH_MAX+1];
|
||||
struct vnode *start_dir, *res;
|
||||
int r;
|
||||
|
||||
*resolve->l_vnode = NULL;
|
||||
*resolve->l_vmp = NULL;
|
||||
|
||||
/* Is the path absolute or relative? Initialize 'start_dir' accordingly. */
|
||||
start_dir = (resolve->l_path[0] == '/' ? rfp->fp_rd : rfp->fp_wd);
|
||||
|
@ -195,8 +199,12 @@ struct fproc *rfp;
|
|||
struct vmnt *vmp;
|
||||
|
||||
vmp = find_vmnt(start_dir->v_fs_e);
|
||||
if (lock_vmnt(vmp, resolve->l_vmnt_lock) != EBUSY)
|
||||
r = lock_vmnt(vmp, resolve->l_vmnt_lock);
|
||||
if (r == EDEADLK)
|
||||
return(NULL);
|
||||
else if (r == OK)
|
||||
*resolve->l_vmp = vmp;
|
||||
|
||||
lock_vnode(start_dir, resolve->l_vnode_lock);
|
||||
*resolve->l_vnode = start_dir;
|
||||
dup_vnode(start_dir);
|
||||
|
@ -285,6 +293,8 @@ struct fproc *rfp;
|
|||
if ((r = lock_vmnt(vmpres, resolve->l_vmnt_lock)) != OK) {
|
||||
if (r == EBUSY) /* vmnt already locked */
|
||||
vmpres = NULL;
|
||||
else
|
||||
return(r);
|
||||
}
|
||||
*(resolve->l_vmp) = vmpres;
|
||||
|
||||
|
@ -320,7 +330,7 @@ struct fproc *rfp;
|
|||
vmp = NULL;
|
||||
} else if (r == EENTERMOUNT) {
|
||||
/* Entering a new partition */
|
||||
dir_vp = 0;
|
||||
dir_vp = NULL;
|
||||
/* Start node is now the mounted partition's root node */
|
||||
for (vmp = &vmnt[0]; vmp != &vmnt[NR_MNTS]; ++vmp) {
|
||||
if (vmp->m_dev != NO_DEV && vmp->m_mounted_on) {
|
||||
|
@ -374,6 +384,8 @@ struct fproc *rfp;
|
|||
if ((r = lock_vmnt(vmpres, resolve->l_vmnt_lock)) != OK) {
|
||||
if (r == EBUSY)
|
||||
vmpres = NULL; /* Already locked */
|
||||
else
|
||||
return(r);
|
||||
}
|
||||
*(resolve->l_vmp) = vmpres;
|
||||
|
||||
|
|
|
@ -50,14 +50,14 @@ PUBLIC int do_pipe()
|
|||
struct vmnt *vmp;
|
||||
struct node_details res;
|
||||
|
||||
/* Get a lock on PFS */
|
||||
if ((vmp = find_vmnt(PFS_PROC_NR)) == NULL) panic("PFS gone");
|
||||
if ((r = lock_vmnt(vmp, VMNT_WRITE)) != OK) return(r);
|
||||
|
||||
/* See if a free vnode is available */
|
||||
if ((vp = get_free_vnode()) == NULL) return(err_code);
|
||||
lock_vnode(vp, VNODE_OPCL);
|
||||
|
||||
/* Get a lock on PFS */
|
||||
if ((vmp = find_vmnt(PFS_PROC_NR)) == NULL) panic("PFS gone");
|
||||
lock_vmnt(vmp, VMNT_WRITE);
|
||||
|
||||
/* Acquire two file descriptors. */
|
||||
rfp = fp;
|
||||
if ((r = get_fd(0, R_BIT, &fil_des[0], &fil_ptr0)) != OK) {
|
||||
|
@ -147,8 +147,13 @@ endpoint_t map_to_fs_e;
|
|||
|
||||
if ((vmp = find_vmnt(map_to_fs_e)) == NULL)
|
||||
panic("Can't map to unknown endpoint");
|
||||
if (lock_vmnt(vmp, VMNT_WRITE) == EBUSY)
|
||||
if ((r = lock_vmnt(vmp, VMNT_WRITE)) != OK) {
|
||||
if (r == EBUSY)
|
||||
vmp = NULL; /* Already locked, do not unlock */
|
||||
else
|
||||
return(r);
|
||||
|
||||
}
|
||||
|
||||
/* Create a temporary mapping of this inode to another FS. Read and write
|
||||
* operations on data will be handled by that FS. The rest by the 'original'
|
||||
|
|
|
@ -141,6 +141,7 @@ _PROTOTYPE( void ds_event, (void) );
|
|||
_PROTOTYPE( int do_fsready, (void) );
|
||||
_PROTOTYPE( int do_mount, (void) );
|
||||
_PROTOTYPE( int do_umount, (void) );
|
||||
_PROTOTYPE( int is_nonedev, (dev_t dev) );
|
||||
_PROTOTYPE( void mount_pfs, (void) );
|
||||
_PROTOTYPE( int mount_fs, (dev_t dev, char fullpath[PATH_MAX+1],
|
||||
endpoint_t fs_e, int rdonly,
|
||||
|
|
|
@ -137,12 +137,17 @@ int rw_flag; /* READING or WRITING */
|
|||
} else if (block_spec) { /* Block special files. */
|
||||
lock_bsf();
|
||||
|
||||
printf("Doing block read_write(%d) from dev %d/ep=%d\n",
|
||||
rw_flag == READING,
|
||||
vp->v_sdev, vp->v_bfs_e);
|
||||
r = req_breadwrite(vp->v_bfs_e, who_e, vp->v_sdev, position,
|
||||
m_in.nbytes, m_in.buffer, rw_flag, &res_pos, &res_cum_io);
|
||||
if (r == OK) {
|
||||
printf("OK res_cum_io = %d\n", res_cum_io);
|
||||
position = res_pos;
|
||||
cum_io += res_cum_io;
|
||||
}
|
||||
} else
|
||||
printf("Failed with %d\n", r);
|
||||
|
||||
unlock_bsf();
|
||||
} else { /* Regular files */
|
||||
|
|
|
@ -129,6 +129,8 @@ PUBLIC int lock_vmnt(struct vmnt *vmp, tll_access_t locktype)
|
|||
|
||||
initial_locktype = (locktype == VMNT_EXCL) ? VMNT_WRITE : locktype;
|
||||
|
||||
if (vmp->m_fs_e == who_e) return(EDEADLK);
|
||||
|
||||
r = tll_lock(&vmp->m_lock, initial_locktype);
|
||||
|
||||
if (r == EBUSY) return(r);
|
||||
|
|
Loading…
Reference in a new issue