From 823e42c3e38200dd6145bd549bdedf1301de0613 Mon Sep 17 00:00:00 2001 From: Thomas Veerman Date: Wed, 26 Oct 2011 13:28:41 +0000 Subject: [PATCH] Make AVFS deal intelligently with back calling FSes PUFFS file systems need to make back calls for every operation we send to them. Consequently, they cannot handle block reads and writes themselves. Instead, the root file system has to do it (for now). When the mount operation causes an FS to make a back call, AVFS now concludes that every block read and write for that FS has to go through the root file system. --- servers/avfs/comm.c | 1 + servers/avfs/main.c | 18 ++++++++---------- servers/avfs/mount.c | 25 +++++++++++++------------ servers/avfs/open.c | 3 ++- servers/avfs/vmnt.h | 2 ++ servers/avfs/worker.c | 5 ++++- 6 files changed, 30 insertions(+), 24 deletions(-) diff --git a/servers/avfs/comm.c b/servers/avfs/comm.c index 06c08e49b..8546622ac 100644 --- a/servers/avfs/comm.c +++ b/servers/avfs/comm.c @@ -82,6 +82,7 @@ PUBLIC int fs_sendrec(endpoint_t fs_e, message *reqmp) if ((vmp = find_vmnt(fs_e)) == NULL) panic("Trying to talk to non-existent FS"); + if (fs_e == fp->fp_endpoint) return(EDEADLK); if (!force_sync) { fp->fp_sendrec = reqmp; /* Where to store request and reply */ diff --git a/servers/avfs/main.c b/servers/avfs/main.c index 61e3ac525..135ab38d8 100644 --- a/servers/avfs/main.c +++ b/servers/avfs/main.c @@ -144,17 +144,23 @@ PRIVATE void handle_work(void *(*func)(void *arg)) if ((vmp = find_vmnt(who_e)) != NULL) { /* A back call or dev result from an FS endpoint */ + + /* When an FS point has to make a callback in order to mount, force + * its device to a "none device" so block reads/writes will be handled + * by ROOT_FS_E. + */ + if (vmp->m_flags & VMNT_MOUNTING) + vmp->m_flags |= VMNT_FORCEROOTBSF; + if (worker_available() == 0) { /* No worker threads available to handle call */ if (deadlock_resolving) { /* Already trying to resolve a deadlock, can't * handle more, sorry */ - reply(who_e, EAGAIN); return; } deadlock_resolving = 1; - vmp->m_flags |= VMNT_BACKCALL; dl_worker_start(func); return; } @@ -198,10 +204,6 @@ PRIVATE void *do_async_dev_result(void *arg) select_reply2(m_in.m_source, m_in.DEV_MINOR, m_in.DEV_SEL_OPS); if (deadlock_resolving) { - struct vmnt *vmp; - if ((vmp = find_vmnt(who_e)) != NULL) - vmp->m_flags &= ~VMNT_BACKCALL; - if (fp != NULL && fp->fp_wtid == dl_worker.w_tid) deadlock_resolving = 0; } @@ -380,7 +382,6 @@ PRIVATE void *do_work(void *arg) int error, i; struct job my_job; struct fproc *rfp; - struct vmnt *vmp; my_job = *((struct job *) arg); fp = my_job.j_fp; @@ -425,9 +426,6 @@ PRIVATE void *do_work(void *arg) /* Copy the results back to the user and send reply. */ if (error != SUSPEND) { if (deadlock_resolving) { - if ((vmp = find_vmnt(who_e)) != NULL) - vmp->m_flags &= ~VMNT_BACKCALL; - if (fp->fp_wtid == dl_worker.w_tid) deadlock_resolving = 0; } diff --git a/servers/avfs/mount.c b/servers/avfs/mount.c index 151e63a7d..656995732 100644 --- a/servers/avfs/mount.c +++ b/servers/avfs/mount.c @@ -241,11 +241,9 @@ char mount_label[LABEL_MAX] ) /* XXX: move this upwards before lookup after proper locking. */ /* We'll need a vnode for the root inode */ if ((root_node = get_free_vnode()) == NULL || dev == 266) { - if (vp != NULL) { - unlock_vnode(vp); - put_vnode(vp); - } + unlock_vnode(vp); unlock_vmnt(new_vmp); + put_vnode(vp); return(err_code); } @@ -258,19 +256,22 @@ char mount_label[LABEL_MAX] ) else new_vmp->m_flags &= ~VMNT_READONLY; /* Tell FS which device to mount */ + new_vmp->m_flags |= VMNT_MOUNTING; r = req_readsuper(fs_e, label, dev, rdonly, isroot, &res, &con_reqs); + new_vmp->m_flags &= ~VMNT_MOUNTING; + if (r != OK) { - if (vp != NULL) { - unlock_vnode(vp); - put_vnode(vp); - } new_vmp->m_fs_e = NONE; new_vmp->m_dev = NO_DEV; unlock_vnode(root_node); + unlock_vnode(vp); unlock_vmnt(new_vmp); + put_vnode(vp); return(r); } + lock_bsf(); + /* Fill in root node's fields */ root_node->v_fs_e = res.fs_e; root_node->v_inode_nr = res.inode_nr; @@ -291,8 +292,6 @@ char mount_label[LABEL_MAX] ) new_vmp->m_comm.c_max_reqs = con_reqs; new_vmp->m_comm.c_cur_reqs = 0; - lock_bsf(); - if (mount_root) { /* Superblock and root node already read. * Nothing else can go wrong. Perform the mount. */ @@ -340,6 +339,7 @@ char mount_label[LABEL_MAX] ) put_vnode(vp); put_vnode(root_node); new_vmp->m_dev = NO_DEV; + new_vmp->m_flags = 0; unlock_bsf(); return(r); } @@ -353,14 +353,15 @@ char mount_label[LABEL_MAX] ) if (is_nonedev(dev)) alloc_nonedev(dev); /* The new FS will handle block I/O requests for its device now. */ - update_bspec(dev, fs_e, 0 /* Don't send new driver endpoint */); + if (!(new_vmp->m_flags & VMNT_FORCEROOTBSF)) + update_bspec(dev, fs_e, 0 /* Don't send new driver endpoint */); unlock_vnode(vp); unlock_vnode(root_node); unlock_vmnt(new_vmp); unlock_bsf(); - return(r); + return(OK); } diff --git a/servers/avfs/open.c b/servers/avfs/open.c index 1655fd2f6..dd88fed06 100644 --- a/servers/avfs/open.c +++ b/servers/avfs/open.c @@ -181,8 +181,9 @@ PRIVATE int common_open(char path[PATH_MAX], int oflags, mode_t omode) 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 && - !is_nonedev(vmp->m_dev)) + !(vmp->m_flags & VMNT_FORCEROOTBSF)) { vp->v_bfs_e = vmp->m_fs_e; + } /* Get the driver endpoint of the block spec device */ major_dev = major(vp->v_sdev); diff --git a/servers/avfs/vmnt.h b/servers/avfs/vmnt.h index 3143f045e..510502c01 100644 --- a/servers/avfs/vmnt.h +++ b/servers/avfs/vmnt.h @@ -15,6 +15,8 @@ EXTERN struct vmnt { /* vmnt flags */ #define VMNT_READONLY 01 /* Device mounted readonly */ #define VMNT_BACKCALL 02 /* FS did back call */ +#define VMNT_MOUNTING 04 /* Device is being mounted */ +#define VMNT_FORCEROOTBSF 010 /* Force usage of none-device */ /* vmnt lock types mapping */ #define VMNT_READ TLL_READ diff --git a/servers/avfs/worker.c b/servers/avfs/worker.c index 01ce6705b..f17989276 100644 --- a/servers/avfs/worker.c +++ b/servers/avfs/worker.c @@ -299,7 +299,10 @@ PUBLIC void worker_signal(struct worker_thread *worker) PUBLIC void worker_stop(struct worker_thread *worker) { ASSERTW(worker); /* Make sure we have a valid thread */ - worker->w_job.j_m_in.m_type = EIO; + if (worker->w_job.j_fp) + worker->w_job.j_fp->fp_sendrec->m_type = EIO; + else + worker->w_job.j_m_in.m_type = EIO; worker_wake(worker); } -- 2.44.0