xref: /minix/minix/servers/vfs/comm.c (revision 7f5f010b)
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