#include "fs.h" #include "glo.h" #include "vmnt.h" #include "fproc.h" #include #include static int sendmsg(struct vmnt *vmp, struct worker_thread *wp); static int queuemsg(struct vmnt *vmp); /*===========================================================================* * sendmsg * *===========================================================================*/ static int sendmsg(struct vmnt *vmp, struct worker_thread *wp) { /* This is the low level function that sends requests to FS processes. */ int r, transid; vmp->m_comm.c_cur_reqs++; /* One more request awaiting a reply */ transid = wp->w_tid + VFS_TRANSID; wp->w_fs_sendrec->m_type = TRNS_ADD_ID(wp->w_fs_sendrec->m_type, transid); wp->w_task = vmp->m_fs_e; if ((r = asynsend3(vmp->m_fs_e, wp->w_fs_sendrec, AMF_NOREPLY)) != OK) { printf("VFS: sendmsg: error sending message. " "FS_e: %d req_nr: %d err: %d\n", vmp->m_fs_e, wp->w_fs_sendrec->m_type, r); util_stacktrace(); return(r); } return(r); } /*===========================================================================* * send_work * *===========================================================================*/ void send_work(void) { /* Try to send out as many requests as possible */ struct vmnt *vmp; if (sending == 0) return; for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; vmp++) fs_sendmore(vmp); } /*===========================================================================* * fs_cancel * *===========================================================================*/ void fs_cancel(struct vmnt *vmp) { /* Cancel all pending requests for this vmp */ struct worker_thread *worker; while ((worker = vmp->m_comm.c_req_queue) != NULL) { vmp->m_comm.c_req_queue = worker->w_next; worker->w_next = NULL; sending--; worker_stop(worker); } } /*===========================================================================* * fs_sendmore * *===========================================================================*/ void fs_sendmore(struct vmnt *vmp) { struct worker_thread *worker; /* Can we send more requests? */ if (vmp->m_fs_e == NONE) return; if ((worker = vmp->m_comm.c_req_queue) == NULL) /* No process is queued */ return; if (vmp->m_comm.c_cur_reqs >= vmp->m_comm.c_max_reqs)/*No room to send more*/ return; if (vmp->m_flags & VMNT_CALLBACK) /* Hold off for now */ return; vmp->m_comm.c_req_queue = worker->w_next; /* Remove head */ worker->w_next = NULL; sending--; assert(sending >= 0); (void) sendmsg(vmp, worker); } /*===========================================================================* * drv_sendrec * *===========================================================================*/ int drv_sendrec(endpoint_t drv_e, message *reqmp) { int r; struct dmap *dp; if ((dp = get_dmap(drv_e)) == NULL) panic("driver endpoint %d invalid", drv_e); lock_dmap(dp); if (dp->dmap_servicing != NONE) panic("driver locking inconsistency"); dp->dmap_servicing = self->w_tid; self->w_task = drv_e; self->w_drv_sendrec = reqmp; if ((r = asynsend3(drv_e, self->w_drv_sendrec, AMF_NOREPLY)) == OK) { /* Yield execution until we've received the reply */ worker_wait(); } else { printf("VFS: drv_sendrec: error sending msg to driver %d: %d\n", drv_e, r); util_stacktrace(); } dp->dmap_servicing = NONE; self->w_task = NONE; self->w_drv_sendrec = NULL; unlock_dmap(dp); return(OK); } /*===========================================================================* * fs_sendrec * *===========================================================================*/ int fs_sendrec(endpoint_t fs_e, message *reqmp) { struct vmnt *vmp; int r; if ((vmp = find_vmnt(fs_e)) == NULL) { printf("Trying to talk to non-existent FS endpoint %d\n", fs_e); return(EIO); } if (fs_e == fp->fp_endpoint) return(EDEADLK); self->w_fs_sendrec = reqmp; /* Where to store request and reply */ /* Find out whether we can send right away or have to enqueue */ if ( !(vmp->m_flags & VMNT_CALLBACK) && vmp->m_comm.c_cur_reqs < vmp->m_comm.c_max_reqs) { /* There's still room to send more and no proc is queued */ r = sendmsg(vmp, self); } else { r = queuemsg(vmp); } self->w_next = NULL; /* End of list */ if (r != OK) return(r); worker_wait(); /* Yield execution until we've received the reply. */ return(reqmp->m_type); } /*===========================================================================* * queuemsg * *===========================================================================*/ static int queuemsg(struct vmnt *vmp) { /* Put request on queue for vmnt */ struct worker_thread *queue; if (vmp->m_comm.c_req_queue == NULL) { vmp->m_comm.c_req_queue = self; } else { /* Walk the list ... */ queue = vmp->m_comm.c_req_queue; while (queue->w_next != NULL) queue = queue->w_next; /* ... and append this worker */ queue->w_next = self; } self->w_next = NULL; /* End of list */ sending++; return(OK); }