kernel: vm kernel call can't suspend
[minix.git] / drivers / fbd / fbd.c
blob87faf6b65e1f66677ac13f625c47e23138c2afd5
1 /* Faulty Block Device (fault injection proxy), by D.C. van Moolenbroek */
2 #include <stdlib.h>
3 #include <minix/drivers.h>
4 #include <minix/blockdriver.h>
5 #include <minix/drvlib.h>
6 #include <minix/ioctl.h>
7 #include <sys/ioc_fbd.h>
8 #include <minix/ds.h>
9 #include <minix/optset.h>
10 #include <assert.h>
12 #include "rule.h"
14 /* Constants. */
15 #define BUF_SIZE (NR_IOREQS * CLICK_SIZE) /* 256k */
17 /* Function declarations. */
18 static int fbd_open(dev_t minor, int access);
19 static int fbd_close(dev_t minor);
20 static int fbd_transfer(dev_t minor, int do_write, u64_t position,
21 endpoint_t endpt, iovec_t *iov, unsigned int nr_req, int flags);
22 static int fbd_ioctl(dev_t minor, unsigned int request, endpoint_t endpt,
23 cp_grant_id_t grant);
25 /* Variables. */
26 static char *fbd_buf; /* scratch buffer */
28 static char driver_label[32] = ""; /* driver DS label */
29 static dev_t driver_minor = -1; /* driver's partition minor to use */
30 static endpoint_t driver_endpt; /* driver endpoint */
32 /* Entry points to this driver. */
33 static struct blockdriver fbd_dtab = {
34 BLOCKDRIVER_TYPE_OTHER, /* do not handle partition requests */
35 fbd_open, /* open or mount request, initialize device */
36 fbd_close, /* release device */
37 fbd_transfer, /* do the I/O */
38 fbd_ioctl, /* perform I/O control request */
39 NULL, /* nothing to clean up */
40 NULL, /* we will not be asked about partitions */
41 NULL, /* we will not be asked for geometry */
42 NULL, /* ignore leftover hardware interrupts */
43 NULL, /* ignore alarms */
44 NULL, /* ignore other messages */
45 NULL /* no multithreading support */
48 /* Options supported by this driver. */
49 static struct optset optset_table[] = {
50 { "label", OPT_STRING, driver_label, sizeof(driver_label) },
51 { "minor", OPT_INT, &driver_minor, 10 },
52 { NULL, 0, NULL, 0 }
55 /*===========================================================================*
56 * sef_cb_init_fresh *
57 *===========================================================================*/
58 static int sef_cb_init_fresh(int type, sef_init_info_t *UNUSED(info))
60 clock_t uptime;
61 int r;
63 /* Parse the given parameters. */
64 if (env_argc > 1)
65 optset_parse(optset_table, env_argv[1]);
67 if (driver_label[0] == '\0')
68 panic("no driver label given");
70 if (ds_retrieve_label_endpt(driver_label, &driver_endpt))
71 panic("unable to resolve driver label");
73 if (driver_minor > 255)
74 panic("no or invalid driver minor given");
76 #if DEBUG
77 printf("FBD: driver label '%s' (endpt %d), minor %d\n",
78 driver_label, driver_endpt, driver_minor);
79 #endif
81 /* Initialize resources. */
82 fbd_buf = alloc_contig(BUF_SIZE, 0, NULL);
84 assert(fbd_buf != NULL);
86 if ((r = getuptime(&uptime)) != OK)
87 panic("getuptime failed (%d)\n", r);
89 srand48(uptime);
91 /* Announce we are up! */
92 blockdriver_announce(type);
94 return OK;
97 /*===========================================================================*
98 * sef_cb_signal_handler *
99 *===========================================================================*/
100 static void sef_cb_signal_handler(int signo)
102 /* Terminate immediately upon receiving a SIGTERM. */
103 if (signo != SIGTERM) return;
105 #if DEBUG
106 printf("FBD: shutting down\n");
107 #endif
109 /* Clean up resources. */
110 free_contig(fbd_buf, BUF_SIZE);
112 exit(0);
115 /*===========================================================================*
116 * sef_local_startup *
117 *===========================================================================*/
118 static void sef_local_startup(void)
120 /* Register init callbacks. */
121 sef_setcb_init_fresh(sef_cb_init_fresh);
122 sef_setcb_init_restart(sef_cb_init_fresh);
123 sef_setcb_init_lu(sef_cb_init_fresh);
125 /* Register signal callback. */
126 sef_setcb_signal_handler(sef_cb_signal_handler);
128 /* Let SEF perform startup. */
129 sef_startup();
132 /*===========================================================================*
133 * main *
134 *===========================================================================*/
135 int main(int argc, char **argv)
137 /* SEF local startup. */
138 env_setargs(argc, argv);
139 sef_local_startup();
141 /* Call the generic receive loop. */
142 blockdriver_task(&fbd_dtab);
144 return OK;
147 /*===========================================================================*
148 * fbd_open *
149 *===========================================================================*/
150 static int fbd_open(dev_t UNUSED(minor), int access)
152 /* Open a device. */
153 message m;
154 int r;
156 /* We simply forward this request to the real driver. */
157 memset(&m, 0, sizeof(m));
158 m.m_type = BDEV_OPEN;
159 m.BDEV_MINOR = driver_minor;
160 m.BDEV_ACCESS = access;
161 m.BDEV_ID = 0;
163 if ((r = sendrec(driver_endpt, &m)) != OK)
164 panic("sendrec to driver failed (%d)\n", r);
166 if (m.m_type != BDEV_REPLY)
167 panic("invalid reply from driver (%d)\n", m.m_type);
169 return m.BDEV_STATUS;
172 /*===========================================================================*
173 * fbd_close *
174 *===========================================================================*/
175 static int fbd_close(dev_t UNUSED(minor))
177 /* Close a device. */
178 message m;
179 int r;
181 /* We simply forward this request to the real driver. */
182 memset(&m, 0, sizeof(m));
183 m.m_type = BDEV_CLOSE;
184 m.BDEV_MINOR = driver_minor;
185 m.BDEV_ID = 0;
187 if ((r = sendrec(driver_endpt, &m)) != OK)
188 panic("sendrec to driver failed (%d)\n", r);
190 if (m.m_type != BDEV_REPLY)
191 panic("invalid reply from driver (%d)\n", m.m_type);
193 return m.BDEV_STATUS;
196 /*===========================================================================*
197 * fbd_ioctl *
198 *===========================================================================*/
199 static int fbd_ioctl(dev_t UNUSED(minor), unsigned int request,
200 endpoint_t endpt, cp_grant_id_t grant)
202 /* Handle an I/O control request. */
203 cp_grant_id_t gid;
204 message m;
205 int r;
207 /* We only handle the FBD requests, and pass on everything else. */
208 switch (request) {
209 case FBDCADDRULE:
210 case FBDCDELRULE:
211 case FBDCGETRULE:
212 return rule_ctl(request, endpt, grant);
215 assert(grant != GRANT_INVALID);
217 gid = cpf_grant_indirect(driver_endpt, endpt, grant);
218 assert(gid != GRANT_INVALID);
220 memset(&m, 0, sizeof(m));
221 m.m_type = BDEV_IOCTL;
222 m.BDEV_MINOR = driver_minor;
223 m.BDEV_REQUEST = request;
224 m.BDEV_GRANT = gid;
225 m.BDEV_ID = 0;
227 if ((r = sendrec(driver_endpt, &m)) != OK)
228 panic("sendrec to driver failed (%d)\n", r);
230 if (m.m_type != BDEV_REPLY)
231 panic("invalid reply from driver (%d)\n", m.m_type);
233 cpf_revoke(gid);
235 return m.BDEV_STATUS;
238 /*===========================================================================*
239 * fbd_transfer_direct *
240 *===========================================================================*/
241 static ssize_t fbd_transfer_direct(int do_write, u64_t position,
242 endpoint_t endpt, iovec_t *iov, unsigned int count, int flags)
244 /* Forward the entire transfer request, without any intervention. */
245 iovec_s_t iovec[NR_IOREQS];
246 cp_grant_id_t grant;
247 message m;
248 int i, r;
250 for (i = 0; i < count; i++) {
251 iovec[i].iov_size = iov[i].iov_size;
252 iovec[i].iov_grant = cpf_grant_indirect(driver_endpt, endpt,
253 iov[i].iov_addr);
254 assert(iovec[i].iov_grant != GRANT_INVALID);
257 grant = cpf_grant_direct(driver_endpt, (vir_bytes) iovec,
258 count * sizeof(iovec[0]), CPF_READ);
259 assert(grant != GRANT_INVALID);
261 m.m_type = do_write ? BDEV_SCATTER : BDEV_GATHER;
262 m.BDEV_MINOR = driver_minor;
263 m.BDEV_COUNT = count;
264 m.BDEV_GRANT = grant;
265 m.BDEV_FLAGS = flags;
266 m.BDEV_ID = 0;
267 m.BDEV_POS_LO = ex64lo(position);
268 m.BDEV_POS_HI = ex64hi(position);
270 if ((r = sendrec(driver_endpt, &m)) != OK)
271 panic("sendrec to driver failed (%d)\n", r);
273 if (m.m_type != BDEV_REPLY)
274 panic("invalid reply from driver (%d)\n", m.m_type);
276 cpf_revoke(grant);
278 for (i = 0; i < count; i++)
279 cpf_revoke(iovec[i].iov_grant);
281 return m.BDEV_STATUS;
284 /*===========================================================================*
285 * fbd_transfer_copy *
286 *===========================================================================*/
287 static ssize_t fbd_transfer_copy(int do_write, u64_t position,
288 endpoint_t endpt, iovec_t *iov, unsigned int count, size_t size,
289 int flags)
291 /* Interpose on the request. */
292 iovec_s_t iovec[NR_IOREQS];
293 struct vscp_vec vscp_vec[SCPVEC_NR];
294 cp_grant_id_t grant;
295 size_t off, len;
296 message m;
297 char *ptr;
298 int i, j, r;
299 ssize_t rsize;
301 assert(count > 0 && count <= SCPVEC_NR);
303 if (size > BUF_SIZE) {
304 printf("FBD: allocating memory for %d bytes\n", size);
306 ptr = alloc_contig(size, 0, NULL);
308 assert(ptr != NULL);
310 else ptr = fbd_buf;
312 /* For write operations, first copy in the data to write. */
313 if (do_write) {
314 for (i = off = 0; i < count; i++) {
315 len = iov[i].iov_size;
317 vscp_vec[i].v_from = endpt;
318 vscp_vec[i].v_to = SELF;
319 vscp_vec[i].v_gid = iov[i].iov_addr;
320 vscp_vec[i].v_offset = 0;
321 vscp_vec[i].v_addr = (vir_bytes) (ptr + off);
322 vscp_vec[i].v_bytes = len;
324 off += len;
327 if ((r = sys_vsafecopy(vscp_vec, i)) != OK)
328 panic("vsafecopy failed (%d)\n", r);
330 /* Trigger write hook. */
331 rule_io_hook(ptr, size, position, FBD_FLAG_WRITE);
334 /* Allocate grants for the data, in the same chunking as the original
335 * vector. This avoids performance fluctuations with bad hardware as
336 * observed with the filter driver.
338 for (i = off = 0; i < count; i++) {
339 len = iov[i].iov_size;
341 iovec[i].iov_size = len;
342 iovec[i].iov_grant = cpf_grant_direct(driver_endpt,
343 (vir_bytes) (ptr + off), len,
344 do_write ? CPF_READ : CPF_WRITE);
345 assert(iovec[i].iov_grant != GRANT_INVALID);
347 off += len;
350 grant = cpf_grant_direct(driver_endpt, (vir_bytes) iovec,
351 count * sizeof(iovec[0]), CPF_READ);
352 assert(grant != GRANT_INVALID);
354 m.m_type = do_write ? BDEV_SCATTER : BDEV_GATHER;
355 m.BDEV_MINOR = driver_minor;
356 m.BDEV_COUNT = count;
357 m.BDEV_GRANT = grant;
358 m.BDEV_FLAGS = flags;
359 m.BDEV_ID = 0;
360 m.BDEV_POS_LO = ex64lo(position);
361 m.BDEV_POS_HI = ex64hi(position);
363 if ((r = sendrec(driver_endpt, &m)) != OK)
364 panic("sendrec to driver failed (%d)\n", r);
366 if (m.m_type != BDEV_REPLY)
367 panic("invalid reply from driver (%d)\n", m.m_type);
369 cpf_revoke(grant);
371 for (i = 0; i < count; i++)
372 cpf_revoke(iovec[i].iov_grant);
374 /* For read operations, finish by copying out the data read. */
375 if (!do_write) {
376 /* Trigger read hook. */
377 rule_io_hook(ptr, size, position, FBD_FLAG_READ);
379 /* Upon success, copy back whatever has been processed. */
380 rsize = m.BDEV_STATUS;
381 for (i = j = off = 0; rsize > 0 && i < count; i++) {
382 len = MIN(rsize, iov[i].iov_size);
384 vscp_vec[j].v_from = SELF;
385 vscp_vec[j].v_to = endpt;
386 vscp_vec[j].v_gid = iov[i].iov_addr;
387 vscp_vec[j].v_offset = 0;
388 vscp_vec[j].v_addr = (vir_bytes) (ptr + off);
389 vscp_vec[j].v_bytes = len;
391 off += len;
392 rsize -= len;
393 j++;
396 if (j > 0 && (r = sys_vsafecopy(vscp_vec, j)) != OK)
397 panic("vsafecopy failed (%d)\n", r);
400 if (ptr != fbd_buf)
401 free_contig(ptr, size);
403 return m.BDEV_STATUS;
406 /*===========================================================================*
407 * fbd_transfer *
408 *===========================================================================*/
409 static int fbd_transfer(dev_t UNUSED(minor), int do_write, u64_t position,
410 endpoint_t endpt, iovec_t *iov, unsigned int nr_req, int flags)
412 /* Transfer data from or to the device. */
413 unsigned count;
414 size_t size, osize;
415 int i, hooks;
416 ssize_t r;
418 /* Compute the total size of the request. */
419 for (size = i = 0; i < nr_req; i++)
420 size += iov[i].iov_size;
422 osize = size;
423 count = nr_req;
425 hooks = rule_find(position, size,
426 do_write ? FBD_FLAG_WRITE : FBD_FLAG_READ);
428 #if DEBUG
429 printf("FBD: %s operation for pos %"PRIx64" size %u -> hooks %x\n",
430 do_write ? "write" : "read", position, size, hooks);
431 #endif
433 if (hooks & PRE_HOOK)
434 rule_pre_hook(iov, &count, &size, &position);
436 if (count > 0) {
437 if (hooks & IO_HOOK) {
438 r = fbd_transfer_copy(do_write, position, endpt, iov,
439 count, size, flags);
440 } else {
441 r = fbd_transfer_direct(do_write, position, endpt, iov,
442 count, flags);
445 else r = 0;
447 if (hooks & POST_HOOK)
448 rule_post_hook(osize, &r);
450 #if DEBUG
451 printf("FBD: returning %d\n", r);
452 #endif
454 return r;