Fixed extern declaration from pointer to array
[minix.git] / servers / mfs / device.c
blobb428291794432eefbbaee675398d10c5cb84c649
1 #include "fs.h"
2 #include <fcntl.h>
3 #include <assert.h>
4 #include <minix/callnr.h>
5 #include <minix/com.h>
6 #include <minix/endpoint.h>
7 #include <minix/ioctl.h>
8 #include <minix/safecopies.h>
9 #include <minix/u64.h>
10 #include <string.h>
11 #include "inode.h"
12 #include "super.h"
13 #include "const.h"
14 #include "drivers.h"
16 #include <minix/vfsif.h>
18 PRIVATE int dummyproc;
20 FORWARD _PROTOTYPE( int safe_io_conversion, (endpoint_t,
21 cp_grant_id_t *, int *, cp_grant_id_t *, int, endpoint_t *,
22 void **, int *, vir_bytes));
23 FORWARD _PROTOTYPE( void safe_io_cleanup, (cp_grant_id_t, cp_grant_id_t *,
24 int));
25 FORWARD _PROTOTYPE( int gen_opcl, (endpoint_t driver_e, int op,
26 Dev_t dev, int proc_e, int flags) );
27 FORWARD _PROTOTYPE( int gen_io, (int task_nr, message *mess_ptr) );
30 /*===========================================================================*
31 * fs_new_driver *
32 *===========================================================================*/
33 PUBLIC int fs_new_driver(void)
35 /* New driver endpoint for this device */
36 driver_endpoints[(fs_m_in.REQ_DEV >> MAJOR) & BYTE].driver_e =
37 fs_m_in.REQ_DRIVER_E;
38 return(OK);
42 /*===========================================================================*
43 * safe_io_conversion *
44 *===========================================================================*/
45 PRIVATE int safe_io_conversion(driver, gid, op, gids, gids_size,
46 io_ept, buf, vec_grants, bytes)
47 endpoint_t driver;
48 cp_grant_id_t *gid;
49 int *op;
50 cp_grant_id_t *gids;
51 int gids_size;
52 endpoint_t *io_ept;
53 void **buf;
54 int *vec_grants;
55 vir_bytes bytes;
57 int access = 0, size;
58 int j;
59 iovec_t *v;
60 static iovec_t *new_iovec;
62 STATICINIT(new_iovec, NR_IOREQS);
64 /* Number of grants allocated in vector I/O. */
65 *vec_grants = 0;
67 /* Driver can handle it - change request to a safe one. */
69 *gid = GRANT_INVALID;
71 switch(*op) {
72 case MFS_DEV_READ:
73 case MFS_DEV_WRITE:
74 /* Change to safe op. */
75 *op = *op == MFS_DEV_READ ? DEV_READ_S : DEV_WRITE_S;
77 if((*gid=cpf_grant_direct(driver, (vir_bytes) *buf, bytes,
78 *op == DEV_READ_S?CPF_WRITE:CPF_READ))<0) {
79 panic(__FILE__,"cpf_grant_magic of buffer failed\n", NO_NUM);
82 break;
83 case MFS_DEV_GATHER:
84 case MFS_DEV_SCATTER:
85 /* Change to safe op. */
86 *op = *op == MFS_DEV_GATHER ? DEV_GATHER_S : DEV_SCATTER_S;
88 /* Grant access to my new i/o vector. */
89 if((*gid = cpf_grant_direct(driver, (vir_bytes) new_iovec,
90 bytes * sizeof(iovec_t),
91 CPF_READ | CPF_WRITE)) < 0) {
92 panic(__FILE__, "cpf_grant_direct of vector failed", NO_NUM);
94 v = (iovec_t *) *buf;
95 /* Grant access to i/o buffers. */
96 for(j = 0; j < bytes; j++) {
97 if(j >= NR_IOREQS)
98 panic(__FILE__, "vec too big", bytes);
99 new_iovec[j].iov_addr = gids[j] =
100 cpf_grant_direct(driver, (vir_bytes) v[j].iov_addr,
101 v[j].iov_size,
102 *op == DEV_GATHER_S ? CPF_WRITE : CPF_READ);
103 if(!GRANT_VALID(gids[j])) {
104 panic(__FILE__, "mfs: grant to iovec buf failed",
105 NO_NUM);
107 new_iovec[j].iov_size = v[j].iov_size;
108 (*vec_grants)++;
111 /* Set user's vector to the new one. */
112 *buf = new_iovec;
113 break;
116 /* If we have converted to a safe operation, I/O
117 * endpoint becomes FS if it wasn't already.
119 if(GRANT_VALID(*gid)) {
120 *io_ept = SELF_E;
121 return 1;
124 /* Not converted to a safe operation (because there is no
125 * copying involved in this operation).
127 return 0;
130 /*===========================================================================*
131 * safe_io_cleanup *
132 *===========================================================================*/
133 PRIVATE void safe_io_cleanup(gid, gids, gids_size)
134 cp_grant_id_t gid;
135 cp_grant_id_t *gids;
136 int gids_size;
138 /* Free resources (specifically, grants) allocated by safe_io_conversion(). */
139 int j;
141 cpf_revoke(gid);
143 for(j = 0; j < gids_size; j++)
144 cpf_revoke(gids[j]);
146 return;
149 /*===========================================================================*
150 * block_dev_io *
151 *===========================================================================*/
152 PUBLIC int block_dev_io(op, dev, proc_e, buf, pos, bytes, flags)
153 int op; /* MFS_DEV_READ, MFS_DEV_WRITE, etc. */
154 dev_t dev; /* major-minor device number */
155 int proc_e; /* in whose address space is buf? */
156 void *buf; /* virtual address of the buffer */
157 u64_t pos; /* byte position */
158 int bytes; /* how many bytes to transfer */
159 int flags; /* special flags, like O_NONBLOCK */
161 /* Read or write from a device. The parameter 'dev' tells which one. */
162 struct dmap *dp;
163 int r, safe;
164 message m;
165 iovec_t *v;
166 cp_grant_id_t gid = GRANT_INVALID;
167 int vec_grants;
168 int op_used;
169 void *buf_used;
170 static cp_grant_id_t *gids;
171 endpoint_t driver_e;
173 STATICINIT(gids, NR_IOREQS);
175 /* Determine driver endpoint for this device */
176 driver_e = driver_endpoints[(dev >> MAJOR) & BYTE].driver_e;
178 /* See if driver is roughly valid. */
179 if (driver_e == NONE) {
180 printf("MFS(%d) block_dev_io: no driver for dev %x\n", SELF_E, dev);
181 return(EDSTDIED);
184 /* The io vector copying relies on this I/O being for FS itself. */
185 if(proc_e != SELF_E) {
186 printf("MFS(%d) doing block_dev_io for non-self %d\n", SELF_E, proc_e);
187 panic(__FILE__, "doing block_dev_io for non-self", proc_e);
190 /* By default, these are right. */
191 m.IO_ENDPT = proc_e;
192 m.ADDRESS = buf;
193 buf_used = buf;
195 /* Convert parameters to 'safe mode'. */
196 op_used = op;
197 safe = safe_io_conversion(driver_e, &gid,
198 &op_used, gids, NR_IOREQS, &m.IO_ENDPT, &buf_used,
199 &vec_grants, bytes);
201 /* Set up rest of the message. */
202 if (safe) m.IO_GRANT = (char *) gid;
204 m.m_type = op_used;
205 m.DEVICE = (dev >> MINOR) & BYTE;
206 m.POSITION = ex64lo(pos);
207 m.COUNT = bytes;
208 m.HIGHPOS = ex64hi(pos);
210 /* Call the task. */
211 r = sendrec(driver_e, &m);
213 /* As block I/O never SUSPENDs, safe cleanup must be done whether
214 * the I/O succeeded or not. */
215 if (safe) safe_io_cleanup(gid, gids, vec_grants);
217 /* RECOVERY:
218 * - send back dead driver number
219 * - VFS unmaps it, waits for new driver
220 * - VFS sends the new driver endp for the FS proc and the request again
222 if (r != OK) {
223 if (r == EDEADSRCDST || r == EDSTDIED || r == ESRCDIED) {
224 printf("MFS(%d) dead driver %d\n", SELF_E, driver_e);
225 driver_endpoints[(dev >> MAJOR) & BYTE].driver_e = NONE;
226 return r;
227 /*dmap_unmap_by_endpt(task_nr); <- in the VFS proc... */
229 else if (r == ELOCKED) {
230 printf("MFS(%d) ELOCKED talking to %d\n", SELF_E, driver_e);
231 return r;
233 else
234 panic(__FILE__,"call_task: can't send/receive", r);
236 else {
237 /* Did the process we did the sendrec() for get a result? */
238 if (m.REP_ENDPT != proc_e) {
239 printf("MFS(%d) strange device reply from %d, type = %d, proc = %d (not %d) (2) ignored\n", SELF_E, m.m_source, m.m_type, proc_e, m.REP_ENDPT);
240 r = EIO;
244 /* Task has completed. See if call completed. */
245 if (m.REP_STATUS == SUSPEND) {
246 panic(__FILE__, "MFS block_dev_io: driver returned SUSPEND", NO_NUM);
249 if(buf != buf_used && r == OK) {
250 memcpy(buf, buf_used, bytes * sizeof(iovec_t));
253 return(m.REP_STATUS);
256 /*===========================================================================*
257 * dev_open *
258 *===========================================================================*/
259 PUBLIC int dev_open(driver_e, dev, proc, flags)
260 endpoint_t driver_e;
261 dev_t dev; /* device to open */
262 int proc; /* process to open for */
263 int flags; /* mode bits and flags */
265 int major, r;
267 /* Determine the major device number call the device class specific
268 * open/close routine. (This is the only routine that must check the
269 * device number for being in range. All others can trust this check.)
271 major = (dev >> MAJOR) & BYTE;
272 if (major >= NR_DEVICES) major = 0;
273 r = gen_opcl(driver_e, DEV_OPEN, dev, proc, flags);
274 if (r == SUSPEND) panic(__FILE__,"suspend on open from", NO_NUM);
275 return(r);
279 /*===========================================================================*
280 * dev_close *
281 *===========================================================================*/
282 PUBLIC void dev_close(driver_e, dev)
283 endpoint_t driver_e;
284 dev_t dev; /* device to close */
286 (void) gen_opcl(driver_e, DEV_CLOSE, dev, 0, 0);
290 /*===========================================================================*
291 * gen_opcl *
292 *===========================================================================*/
293 PRIVATE int gen_opcl(driver_e, op, dev, proc_e, flags)
294 endpoint_t driver_e;
295 int op; /* operation, DEV_OPEN or DEV_CLOSE */
296 dev_t dev; /* device to open or close */
297 int proc_e; /* process to open/close for */
298 int flags; /* mode bits and flags */
300 /* Called from the dmap struct in table.c on opens & closes of special files.*/
301 message dev_mess;
303 dev_mess.m_type = op;
304 dev_mess.DEVICE = (dev >> MINOR) & BYTE;
305 dev_mess.IO_ENDPT = proc_e;
306 dev_mess.COUNT = flags;
308 /* Call the task. */
309 gen_io(driver_e, &dev_mess);
311 return(dev_mess.REP_STATUS);
315 /*===========================================================================*
316 * gen_io *
317 *===========================================================================*/
318 PRIVATE int gen_io(task_nr, mess_ptr)
319 int task_nr; /* which task to call */
320 message *mess_ptr; /* pointer to message for task */
322 /* All file system I/O ultimately comes down to I/O on major/minor device
323 * pairs. These lead to calls on the following routines via the dmap table.
326 int r, proc_e;
328 proc_e = mess_ptr->IO_ENDPT;
330 r = sendrec(task_nr, mess_ptr);
331 if (r != OK) {
332 if (r == EDEADSRCDST || r == EDSTDIED || r == ESRCDIED) {
333 printf("fs: dead driver %d\n", task_nr);
334 panic(__FILE__, "should handle crashed drivers",
335 NO_NUM);
336 /* dmap_unmap_by_endpt(task_nr); */
337 return r;
339 if (r == ELOCKED) {
340 printf("fs: ELOCKED talking to %d\n", task_nr);
341 return r;
343 panic(__FILE__,"call_task: can't send/receive", r);
346 /* Did the process we did the sendrec() for get a result? */
347 if (mess_ptr->REP_ENDPT != proc_e) {
348 printf(
349 "fs: strange device reply from %d, type = %d, proc = %d (not %d) (2) ignored\n",
350 mess_ptr->m_source,
351 mess_ptr->m_type,
352 proc_e,
353 mess_ptr->REP_ENDPT);
354 return(EIO);
357 return(OK);