1 #include "fs.h" 2 #include <minix/vfsif.h> 3 #include <assert.h> 4 #include <string.h> 5 6 static int sendmsg(struct vmnt *vmp, endpoint_t dst, struct worker_thread *wp); 7 static int queuemsg(struct vmnt *vmp); 8 9 /*===========================================================================* 10 * sendmsg * 11 *===========================================================================*/ 12 static int sendmsg(struct vmnt *vmp, endpoint_t dst, struct worker_thread *wp) 13 { 14 /* This is the low level function that sends requests. 15 * Currently to FSes or VM. 16 */ 17 int r, transid; 18 19 if(vmp) vmp->m_comm.c_cur_reqs++; /* One more request awaiting a reply */ 20 transid = wp->w_tid + VFS_TRANSID; 21 wp->w_sendrec->m_type = TRNS_ADD_ID(wp->w_sendrec->m_type, transid); 22 wp->w_task = dst; 23 if ((r = asynsend3(dst, wp->w_sendrec, AMF_NOREPLY)) != OK) { 24 printf("VFS: sendmsg: error sending message. " 25 "dest: %d req_nr: %d err: %d\n", dst, 26 wp->w_sendrec->m_type, r); 27 util_stacktrace(); 28 return(r); 29 } 30 31 return(r); 32 } 33 34 /*===========================================================================* 35 * send_work * 36 *===========================================================================*/ 37 void send_work(void) 38 { 39 /* Try to send out as many requests as possible */ 40 struct vmnt *vmp; 41 42 if (sending == 0) return; 43 for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; vmp++) 44 fs_sendmore(vmp); 45 } 46 47 /*===========================================================================* 48 * fs_cancel * 49 *===========================================================================*/ 50 void fs_cancel(struct vmnt *vmp) 51 { 52 /* Cancel all pending requests for this vmp */ 53 struct worker_thread *worker; 54 55 while ((worker = vmp->m_comm.c_req_queue) != NULL) { 56 vmp->m_comm.c_req_queue = worker->w_next; 57 worker->w_next = NULL; 58 sending--; 59 worker_stop(worker); 60 } 61 } 62 63 /*===========================================================================* 64 * fs_sendmore * 65 *===========================================================================*/ 66 void fs_sendmore(struct vmnt *vmp) 67 { 68 struct worker_thread *worker; 69 70 /* Can we send more requests? */ 71 if (vmp->m_fs_e == NONE) return; 72 if ((worker = vmp->m_comm.c_req_queue) == NULL) /* No process is queued */ 73 return; 74 if (vmp->m_comm.c_cur_reqs >= vmp->m_comm.c_max_reqs)/*No room to send more*/ 75 return; 76 if (vmp->m_flags & VMNT_CALLBACK) /* Hold off for now */ 77 return; 78 79 vmp->m_comm.c_req_queue = worker->w_next; /* Remove head */ 80 worker->w_next = NULL; 81 sending--; 82 assert(sending >= 0); 83 (void) sendmsg(vmp, vmp->m_fs_e, worker); 84 } 85 86 /*===========================================================================* 87 * drv_sendrec * 88 *===========================================================================*/ 89 int drv_sendrec(endpoint_t drv_e, message *reqmp) 90 { 91 int r; 92 struct dmap *dp; 93 94 /* For the CTTY_MAJOR case, we would actually have to lock the device 95 * entry being redirected to. However, the CTTY major only hosts a 96 * character device while this function is used only for block devices. 97 * Thus, we can simply deny the request immediately. 98 */ 99 if (drv_e == CTTY_ENDPT) { 100 printf("VFS: /dev/tty is not a block device!\n"); 101 return EIO; 102 } 103 104 if ((dp = get_dmap(drv_e)) == NULL) 105 panic("driver endpoint %d invalid", drv_e); 106 107 lock_dmap(dp); 108 if (dp->dmap_servicing != INVALID_THREAD) 109 panic("driver locking inconsistency"); 110 dp->dmap_servicing = self->w_tid; 111 self->w_task = drv_e; 112 self->w_drv_sendrec = reqmp; 113 114 if ((r = asynsend3(drv_e, self->w_drv_sendrec, AMF_NOREPLY)) == OK) { 115 /* Yield execution until we've received the reply */ 116 worker_wait(); 117 } else { 118 printf("VFS: drv_sendrec: error sending msg to driver %d: %d\n", 119 drv_e, r); 120 util_stacktrace(); 121 } 122 123 dp->dmap_servicing = INVALID_THREAD; 124 self->w_task = NONE; 125 self->w_drv_sendrec = NULL; 126 unlock_dmap(dp); 127 return(OK); 128 } 129 130 /*===========================================================================* 131 * fs_sendrec * 132 *===========================================================================*/ 133 int fs_sendrec(endpoint_t fs_e, message *reqmp) 134 { 135 struct vmnt *vmp; 136 int r; 137 138 if ((vmp = find_vmnt(fs_e)) == NULL) { 139 printf("Trying to talk to non-existent FS endpoint %d\n", fs_e); 140 return(EIO); 141 } 142 if (fs_e == fp->fp_endpoint) return(EDEADLK); 143 144 self->w_sendrec = reqmp; /* Where to store request and reply */ 145 146 /* Find out whether we can send right away or have to enqueue */ 147 if ( !(vmp->m_flags & VMNT_CALLBACK) && 148 vmp->m_comm.c_cur_reqs < vmp->m_comm.c_max_reqs) { 149 /* There's still room to send more and no proc is queued */ 150 r = sendmsg(vmp, vmp->m_fs_e, self); 151 } else { 152 r = queuemsg(vmp); 153 } 154 self->w_next = NULL; /* End of list */ 155 156 if (r != OK) return(r); 157 158 worker_wait(); /* Yield execution until we've received the reply. */ 159 160 return(reqmp->m_type); 161 } 162 163 /*===========================================================================* 164 * vm_sendrec * 165 *===========================================================================*/ 166 int vm_sendrec(message *reqmp) 167 { 168 int r; 169 170 assert(self); 171 assert(reqmp); 172 173 self->w_sendrec = reqmp; /* Where to store request and reply */ 174 175 r = sendmsg(NULL, VM_PROC_NR, self); 176 177 self->w_next = NULL; /* End of list */ 178 179 if (r != OK) return(r); 180 181 worker_wait(); /* Yield execution until we've received the reply. */ 182 183 return(reqmp->m_type); 184 } 185 186 187 /*===========================================================================* 188 * vm_vfs_procctl_handlemem * 189 *===========================================================================*/ 190 int vm_vfs_procctl_handlemem(endpoint_t ep, 191 vir_bytes mem, vir_bytes len, int flags) 192 { 193 message m; 194 195 /* main thread can not be suspended */ 196 if(!self) return EFAULT; 197 198 memset(&m, 0, sizeof(m)); 199 200 m.m_type = VM_PROCCTL; 201 m.VMPCTL_WHO = ep; 202 m.VMPCTL_PARAM = VMPPARAM_HANDLEMEM; 203 m.VMPCTL_M1 = mem; 204 m.VMPCTL_LEN = len; 205 m.VMPCTL_FLAGS = flags; 206 207 return vm_sendrec(&m); 208 } 209 210 /*===========================================================================* 211 * queuemsg * 212 *===========================================================================*/ 213 static int queuemsg(struct vmnt *vmp) 214 { 215 /* Put request on queue for vmnt */ 216 217 struct worker_thread *queue; 218 219 if (vmp->m_comm.c_req_queue == NULL) { 220 vmp->m_comm.c_req_queue = self; 221 } else { 222 /* Walk the list ... */ 223 queue = vmp->m_comm.c_req_queue; 224 while (queue->w_next != NULL) queue = queue->w_next; 225 226 /* ... and append this worker */ 227 queue->w_next = self; 228 } 229 230 self->w_next = NULL; /* End of list */ 231 sending++; 232 233 return(OK); 234 } 235