Fix locking issues with back calls from FSes

This commit is contained in:
Thomas Veerman 2011-08-19 14:12:07 +00:00
parent 195190912f
commit ae2159c371
10 changed files with 79 additions and 48 deletions

View file

@ -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) {

View file

@ -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();
}

View file

@ -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,7 +287,9 @@ char mount_label[LABEL_MAX] )
root_node->v_vmnt = new_vmp;
root_node->v_dev = new_vmp->m_dev;
if(mount_root) {
lock_bsf();
if (mount_root) {
/* Superblock and root node already read.
* Nothing else can go wrong. Perform the mount. */
new_vmp->m_root_node = root_node;
@ -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.
*/

View file

@ -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 */

View file

@ -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;

View file

@ -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'

View file

@ -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,

View file

@ -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 */

View file

@ -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);