1 /* Faulty Block Device (fault injection proxy), by D.C. van Moolenbroek */
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>
9 #include <minix/optset.h>
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
,
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 },
55 /*===========================================================================*
57 *===========================================================================*/
58 static int sef_cb_init_fresh(int type
, sef_init_info_t
*UNUSED(info
))
63 /* Parse the given parameters. */
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");
77 printf("FBD: driver label '%s' (endpt %d), minor %d\n",
78 driver_label
, driver_endpt
, driver_minor
);
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
);
91 /* Announce we are up! */
92 blockdriver_announce(type
);
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;
106 printf("FBD: shutting down\n");
109 /* Clean up resources. */
110 free_contig(fbd_buf
, BUF_SIZE
);
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. */
132 /*===========================================================================*
134 *===========================================================================*/
135 int main(int argc
, char **argv
)
137 /* SEF local startup. */
138 env_setargs(argc
, argv
);
141 /* Call the generic receive loop. */
142 blockdriver_task(&fbd_dtab
);
147 /*===========================================================================*
149 *===========================================================================*/
150 static int fbd_open(dev_t
UNUSED(minor
), int access
)
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
;
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 /*===========================================================================*
174 *===========================================================================*/
175 static int fbd_close(dev_t
UNUSED(minor
))
177 /* Close a device. */
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
;
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 /*===========================================================================*
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. */
207 /* We only handle the FBD requests, and pass on everything else. */
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
;
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
);
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
];
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
,
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
;
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
);
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
,
291 /* Interpose on the request. */
292 iovec_s_t iovec
[NR_IOREQS
];
293 struct vscp_vec vscp_vec
[SCPVEC_NR
];
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
);
312 /* For write operations, first copy in the data to 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
;
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
);
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
;
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
);
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. */
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
;
396 if (j
> 0 && (r
= sys_vsafecopy(vscp_vec
, j
)) != OK
)
397 panic("vsafecopy failed (%d)\n", r
);
401 free_contig(ptr
, size
);
403 return m
.BDEV_STATUS
;
406 /*===========================================================================*
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. */
418 /* Compute the total size of the request. */
419 for (size
= i
= 0; i
< nr_req
; i
++)
420 size
+= iov
[i
].iov_size
;
425 hooks
= rule_find(position
, size
,
426 do_write
? FBD_FLAG_WRITE
: FBD_FLAG_READ
);
429 printf("FBD: %s operation for pos %"PRIx64
" size %u -> hooks %x\n",
430 do_write
? "write" : "read", position
, size
, hooks
);
433 if (hooks
& PRE_HOOK
)
434 rule_pre_hook(iov
, &count
, &size
, &position
);
437 if (hooks
& IO_HOOK
) {
438 r
= fbd_transfer_copy(do_write
, position
, endpt
, iov
,
441 r
= fbd_transfer_direct(do_write
, position
, endpt
, iov
,
447 if (hooks
& POST_HOOK
)
448 rule_post_hook(osize
, &r
);
451 printf("FBD: returning %d\n", r
);