1433d6423SLionel Sambuc #include "fs.h"
2433d6423SLionel Sambuc #include <minix/vfsif.h>
3433d6423SLionel Sambuc #include <assert.h>
4433d6423SLionel Sambuc #include <string.h>
5433d6423SLionel Sambuc
6433d6423SLionel Sambuc static int sendmsg(struct vmnt *vmp, endpoint_t dst, struct worker_thread *wp);
7433d6423SLionel Sambuc static int queuemsg(struct vmnt *vmp);
8433d6423SLionel Sambuc
9433d6423SLionel Sambuc /*===========================================================================*
10433d6423SLionel Sambuc * sendmsg *
11433d6423SLionel Sambuc *===========================================================================*/
sendmsg(struct vmnt * vmp,endpoint_t dst,struct worker_thread * wp)12433d6423SLionel Sambuc static int sendmsg(struct vmnt *vmp, endpoint_t dst, struct worker_thread *wp)
13433d6423SLionel Sambuc {
14433d6423SLionel Sambuc /* This is the low level function that sends requests.
15433d6423SLionel Sambuc * Currently to FSes or VM.
16433d6423SLionel Sambuc */
17433d6423SLionel Sambuc int r, transid;
18433d6423SLionel Sambuc
19433d6423SLionel Sambuc if(vmp) vmp->m_comm.c_cur_reqs++; /* One more request awaiting a reply */
20433d6423SLionel Sambuc transid = wp->w_tid + VFS_TRANSID;
21433d6423SLionel Sambuc wp->w_sendrec->m_type = TRNS_ADD_ID(wp->w_sendrec->m_type, transid);
22433d6423SLionel Sambuc wp->w_task = dst;
23433d6423SLionel Sambuc if ((r = asynsend3(dst, wp->w_sendrec, AMF_NOREPLY)) != OK) {
24433d6423SLionel Sambuc printf("VFS: sendmsg: error sending message. "
25433d6423SLionel Sambuc "dest: %d req_nr: %d err: %d\n", dst,
26433d6423SLionel Sambuc wp->w_sendrec->m_type, r);
27433d6423SLionel Sambuc util_stacktrace();
28433d6423SLionel Sambuc return(r);
29433d6423SLionel Sambuc }
30433d6423SLionel Sambuc
31433d6423SLionel Sambuc return(r);
32433d6423SLionel Sambuc }
33433d6423SLionel Sambuc
34433d6423SLionel Sambuc /*===========================================================================*
35433d6423SLionel Sambuc * send_work *
36433d6423SLionel Sambuc *===========================================================================*/
send_work(void)37433d6423SLionel Sambuc void send_work(void)
38433d6423SLionel Sambuc {
39433d6423SLionel Sambuc /* Try to send out as many requests as possible */
40433d6423SLionel Sambuc struct vmnt *vmp;
41433d6423SLionel Sambuc
42433d6423SLionel Sambuc if (sending == 0) return;
43433d6423SLionel Sambuc for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; vmp++)
44433d6423SLionel Sambuc fs_sendmore(vmp);
45433d6423SLionel Sambuc }
46433d6423SLionel Sambuc
47433d6423SLionel Sambuc /*===========================================================================*
48433d6423SLionel Sambuc * fs_cancel *
49433d6423SLionel Sambuc *===========================================================================*/
fs_cancel(struct vmnt * vmp)50433d6423SLionel Sambuc void fs_cancel(struct vmnt *vmp)
51433d6423SLionel Sambuc {
52433d6423SLionel Sambuc /* Cancel all pending requests for this vmp */
53433d6423SLionel Sambuc struct worker_thread *worker;
54433d6423SLionel Sambuc
55433d6423SLionel Sambuc while ((worker = vmp->m_comm.c_req_queue) != NULL) {
56433d6423SLionel Sambuc vmp->m_comm.c_req_queue = worker->w_next;
57433d6423SLionel Sambuc worker->w_next = NULL;
58433d6423SLionel Sambuc sending--;
59433d6423SLionel Sambuc worker_stop(worker);
60433d6423SLionel Sambuc }
61433d6423SLionel Sambuc }
62433d6423SLionel Sambuc
63433d6423SLionel Sambuc /*===========================================================================*
64433d6423SLionel Sambuc * fs_sendmore *
65433d6423SLionel Sambuc *===========================================================================*/
fs_sendmore(struct vmnt * vmp)66433d6423SLionel Sambuc void fs_sendmore(struct vmnt *vmp)
67433d6423SLionel Sambuc {
68433d6423SLionel Sambuc struct worker_thread *worker;
69433d6423SLionel Sambuc
70433d6423SLionel Sambuc /* Can we send more requests? */
71433d6423SLionel Sambuc if (vmp->m_fs_e == NONE) return;
72433d6423SLionel Sambuc if ((worker = vmp->m_comm.c_req_queue) == NULL) /* No process is queued */
73433d6423SLionel Sambuc return;
74433d6423SLionel Sambuc if (vmp->m_comm.c_cur_reqs >= vmp->m_comm.c_max_reqs)/*No room to send more*/
75433d6423SLionel Sambuc return;
76433d6423SLionel Sambuc if (vmp->m_flags & VMNT_CALLBACK) /* Hold off for now */
77433d6423SLionel Sambuc return;
78433d6423SLionel Sambuc
79433d6423SLionel Sambuc vmp->m_comm.c_req_queue = worker->w_next; /* Remove head */
80433d6423SLionel Sambuc worker->w_next = NULL;
81433d6423SLionel Sambuc sending--;
82433d6423SLionel Sambuc assert(sending >= 0);
83433d6423SLionel Sambuc (void) sendmsg(vmp, vmp->m_fs_e, worker);
84433d6423SLionel Sambuc }
85433d6423SLionel Sambuc
86433d6423SLionel Sambuc /*===========================================================================*
87433d6423SLionel Sambuc * drv_sendrec *
88433d6423SLionel Sambuc *===========================================================================*/
drv_sendrec(endpoint_t drv_e,message * reqmp)89433d6423SLionel Sambuc int drv_sendrec(endpoint_t drv_e, message *reqmp)
90433d6423SLionel Sambuc {
91433d6423SLionel Sambuc int r;
92433d6423SLionel Sambuc struct dmap *dp;
93433d6423SLionel Sambuc
94433d6423SLionel Sambuc /* For the CTTY_MAJOR case, we would actually have to lock the device
95433d6423SLionel Sambuc * entry being redirected to. However, the CTTY major only hosts a
96433d6423SLionel Sambuc * character device while this function is used only for block devices.
97433d6423SLionel Sambuc * Thus, we can simply deny the request immediately.
98433d6423SLionel Sambuc */
99433d6423SLionel Sambuc if (drv_e == CTTY_ENDPT) {
100433d6423SLionel Sambuc printf("VFS: /dev/tty is not a block device!\n");
101433d6423SLionel Sambuc return EIO;
102433d6423SLionel Sambuc }
103433d6423SLionel Sambuc
104*e3b8d4bbSDavid van Moolenbroek if ((dp = get_dmap_by_endpt(drv_e)) == NULL)
105433d6423SLionel Sambuc panic("driver endpoint %d invalid", drv_e);
106433d6423SLionel Sambuc
107433d6423SLionel Sambuc lock_dmap(dp);
108433d6423SLionel Sambuc if (dp->dmap_servicing != INVALID_THREAD)
109433d6423SLionel Sambuc panic("driver locking inconsistency");
110433d6423SLionel Sambuc dp->dmap_servicing = self->w_tid;
111433d6423SLionel Sambuc self->w_task = drv_e;
112433d6423SLionel Sambuc self->w_drv_sendrec = reqmp;
113433d6423SLionel Sambuc
114433d6423SLionel Sambuc if ((r = asynsend3(drv_e, self->w_drv_sendrec, AMF_NOREPLY)) == OK) {
115433d6423SLionel Sambuc /* Yield execution until we've received the reply */
116433d6423SLionel Sambuc worker_wait();
11729e004d2SDavid van Moolenbroek
118433d6423SLionel Sambuc } else {
119433d6423SLionel Sambuc printf("VFS: drv_sendrec: error sending msg to driver %d: %d\n",
120433d6423SLionel Sambuc drv_e, r);
12129e004d2SDavid van Moolenbroek self->w_drv_sendrec = NULL;
122433d6423SLionel Sambuc }
123433d6423SLionel Sambuc
12429e004d2SDavid van Moolenbroek assert(self->w_drv_sendrec == NULL);
125433d6423SLionel Sambuc dp->dmap_servicing = INVALID_THREAD;
126433d6423SLionel Sambuc self->w_task = NONE;
127433d6423SLionel Sambuc unlock_dmap(dp);
12829e004d2SDavid van Moolenbroek return(r);
129433d6423SLionel Sambuc }
130433d6423SLionel Sambuc
131433d6423SLionel Sambuc /*===========================================================================*
132433d6423SLionel Sambuc * fs_sendrec *
133433d6423SLionel Sambuc *===========================================================================*/
fs_sendrec(endpoint_t fs_e,message * reqmp)134433d6423SLionel Sambuc int fs_sendrec(endpoint_t fs_e, message *reqmp)
135433d6423SLionel Sambuc {
136433d6423SLionel Sambuc struct vmnt *vmp;
137433d6423SLionel Sambuc int r;
138433d6423SLionel Sambuc
139433d6423SLionel Sambuc if ((vmp = find_vmnt(fs_e)) == NULL) {
140433d6423SLionel Sambuc printf("Trying to talk to non-existent FS endpoint %d\n", fs_e);
141433d6423SLionel Sambuc return(EIO);
142433d6423SLionel Sambuc }
143433d6423SLionel Sambuc if (fs_e == fp->fp_endpoint) return(EDEADLK);
144433d6423SLionel Sambuc
14529e004d2SDavid van Moolenbroek assert(self->w_sendrec == NULL);
146433d6423SLionel Sambuc self->w_sendrec = reqmp; /* Where to store request and reply */
147433d6423SLionel Sambuc
148433d6423SLionel Sambuc /* Find out whether we can send right away or have to enqueue */
149433d6423SLionel Sambuc if ( !(vmp->m_flags & VMNT_CALLBACK) &&
150433d6423SLionel Sambuc vmp->m_comm.c_cur_reqs < vmp->m_comm.c_max_reqs) {
151433d6423SLionel Sambuc /* There's still room to send more and no proc is queued */
152433d6423SLionel Sambuc r = sendmsg(vmp, vmp->m_fs_e, self);
153433d6423SLionel Sambuc } else {
154433d6423SLionel Sambuc r = queuemsg(vmp);
155433d6423SLionel Sambuc }
156433d6423SLionel Sambuc self->w_next = NULL; /* End of list */
157433d6423SLionel Sambuc
158433d6423SLionel Sambuc if (r != OK) return(r);
159433d6423SLionel Sambuc
160433d6423SLionel Sambuc worker_wait(); /* Yield execution until we've received the reply. */
161433d6423SLionel Sambuc
16229e004d2SDavid van Moolenbroek assert(self->w_sendrec == NULL);
16329e004d2SDavid van Moolenbroek
16410b7016bSDavid van Moolenbroek r = reqmp->m_type;
16510b7016bSDavid van Moolenbroek if (r == ERESTART) /* ERESTART is used internally, so make sure it is.. */
16610b7016bSDavid van Moolenbroek r = EIO; /* ..not delivered as a result from a file system. */
16710b7016bSDavid van Moolenbroek return(r);
168433d6423SLionel Sambuc }
169433d6423SLionel Sambuc
170433d6423SLionel Sambuc /*===========================================================================*
171433d6423SLionel Sambuc * vm_sendrec *
172433d6423SLionel Sambuc *===========================================================================*/
vm_sendrec(message * reqmp)173433d6423SLionel Sambuc int vm_sendrec(message *reqmp)
174433d6423SLionel Sambuc {
175433d6423SLionel Sambuc int r;
176433d6423SLionel Sambuc
177433d6423SLionel Sambuc assert(self);
178433d6423SLionel Sambuc assert(reqmp);
179433d6423SLionel Sambuc
18029e004d2SDavid van Moolenbroek assert(self->w_sendrec == NULL);
181433d6423SLionel Sambuc self->w_sendrec = reqmp; /* Where to store request and reply */
182433d6423SLionel Sambuc
183433d6423SLionel Sambuc r = sendmsg(NULL, VM_PROC_NR, self);
184433d6423SLionel Sambuc
185433d6423SLionel Sambuc self->w_next = NULL; /* End of list */
186433d6423SLionel Sambuc
187433d6423SLionel Sambuc if (r != OK) return(r);
188433d6423SLionel Sambuc
189433d6423SLionel Sambuc worker_wait(); /* Yield execution until we've received the reply. */
190433d6423SLionel Sambuc
19129e004d2SDavid van Moolenbroek assert(self->w_sendrec == NULL);
19229e004d2SDavid van Moolenbroek
193433d6423SLionel Sambuc return(reqmp->m_type);
194433d6423SLionel Sambuc }
195433d6423SLionel Sambuc
196433d6423SLionel Sambuc
197433d6423SLionel Sambuc /*===========================================================================*
198433d6423SLionel Sambuc * vm_vfs_procctl_handlemem *
199433d6423SLionel Sambuc *===========================================================================*/
vm_vfs_procctl_handlemem(endpoint_t ep,vir_bytes mem,vir_bytes len,int flags)200433d6423SLionel Sambuc int vm_vfs_procctl_handlemem(endpoint_t ep,
201433d6423SLionel Sambuc vir_bytes mem, vir_bytes len, int flags)
202433d6423SLionel Sambuc {
203433d6423SLionel Sambuc message m;
204433d6423SLionel Sambuc
205433d6423SLionel Sambuc /* main thread can not be suspended */
206433d6423SLionel Sambuc if(!self) return EFAULT;
207433d6423SLionel Sambuc
208433d6423SLionel Sambuc memset(&m, 0, sizeof(m));
209433d6423SLionel Sambuc
210433d6423SLionel Sambuc m.m_type = VM_PROCCTL;
211433d6423SLionel Sambuc m.VMPCTL_WHO = ep;
212433d6423SLionel Sambuc m.VMPCTL_PARAM = VMPPARAM_HANDLEMEM;
213433d6423SLionel Sambuc m.VMPCTL_M1 = mem;
214433d6423SLionel Sambuc m.VMPCTL_LEN = len;
215433d6423SLionel Sambuc m.VMPCTL_FLAGS = flags;
216433d6423SLionel Sambuc
217433d6423SLionel Sambuc return vm_sendrec(&m);
218433d6423SLionel Sambuc }
219433d6423SLionel Sambuc
220433d6423SLionel Sambuc /*===========================================================================*
221433d6423SLionel Sambuc * queuemsg *
222433d6423SLionel Sambuc *===========================================================================*/
queuemsg(struct vmnt * vmp)223433d6423SLionel Sambuc static int queuemsg(struct vmnt *vmp)
224433d6423SLionel Sambuc {
225433d6423SLionel Sambuc /* Put request on queue for vmnt */
226433d6423SLionel Sambuc
227433d6423SLionel Sambuc struct worker_thread *queue;
228433d6423SLionel Sambuc
229433d6423SLionel Sambuc if (vmp->m_comm.c_req_queue == NULL) {
230433d6423SLionel Sambuc vmp->m_comm.c_req_queue = self;
231433d6423SLionel Sambuc } else {
232433d6423SLionel Sambuc /* Walk the list ... */
233433d6423SLionel Sambuc queue = vmp->m_comm.c_req_queue;
234433d6423SLionel Sambuc while (queue->w_next != NULL) queue = queue->w_next;
235433d6423SLionel Sambuc
236433d6423SLionel Sambuc /* ... and append this worker */
237433d6423SLionel Sambuc queue->w_next = self;
238433d6423SLionel Sambuc }
239433d6423SLionel Sambuc
240433d6423SLionel Sambuc self->w_next = NULL; /* End of list */
241433d6423SLionel Sambuc sending++;
242433d6423SLionel Sambuc
243433d6423SLionel Sambuc return(OK);
244433d6423SLionel Sambuc }
245