top manpage update
[minix.git] / drivers / filter / driver.c
blob97afc6888c8138e01f284191a5fb53edc61e5c45
1 /* Filter driver - lowest layer - disk driver management */
3 #include "inc.h"
5 /* Drivers. */
6 static struct {
7 char *label;
8 int minor;
9 endpoint_t endpt;
11 int problem; /* one of BD_* */
12 int error; /* one of E*, only relevant if problem>0 */
13 int retries;
14 int kills;
15 } driver[2];
17 /* State variables. */
18 static endpoint_t self_ep;
19 static asynmsg_t amsgtable[2];
21 static int size_known = 0;
22 static u64_t disk_size;
24 static int problem_stats[BD_LAST] = { 0 };
26 /*===========================================================================*
27 * driver_open *
28 *===========================================================================*/
29 static int driver_open(int which)
31 /* Perform an open or close operation on the driver. This is
32 * unfinished code: we should never be doing a blocking sendrec() to
33 * the driver.
35 message msg;
36 cp_grant_id_t gid;
37 struct partition part;
38 sector_t sectors;
39 int r;
41 msg.m_type = DEV_OPEN;
42 msg.DEVICE = driver[which].minor;
43 msg.IO_ENDPT = self_ep;
44 r = sendrec(driver[which].endpt, &msg);
46 if (r != OK) {
47 /* Should we restart the driver now? */
48 printf("Filter: driver_open: sendrec returned %d\n", r);
50 return RET_REDO;
53 if(msg.m_type != TASK_REPLY || msg.REP_STATUS != OK) {
54 printf("Filter: driver_open: sendrec returned %d, %d\n",
55 msg.m_type, msg.REP_STATUS);
57 return RET_REDO;
60 /* Take the opportunity to retrieve the hard disk size. */
61 gid = cpf_grant_direct(driver[which].endpt,
62 (vir_bytes) &part, sizeof(part), CPF_WRITE);
63 if(!GRANT_VALID(gid))
64 panic(__FILE__, "invalid grant", gid);
66 msg.m_type = DEV_IOCTL_S;
67 msg.REQUEST = DIOCGETP;
68 msg.DEVICE = driver[which].minor;
69 msg.IO_ENDPT = self_ep;
70 msg.IO_GRANT = (char *) gid;
72 r = sendrec(driver[which].endpt, &msg);
74 cpf_revoke(gid);
76 if (r != OK || msg.m_type != TASK_REPLY || msg.REP_STATUS != OK) {
77 /* Not sure what to do here, either. */
78 printf("Filter: ioctl(DIOCGETP) returned (%d, %d)\n",
79 r, msg.m_type);
81 return RET_REDO;
84 if(!size_known) {
85 disk_size = part.size;
86 size_known = 1;
87 sectors = div64u(disk_size, SECTOR_SIZE);
88 if(cmp64(mul64u(sectors, SECTOR_SIZE), disk_size)) {
89 printf("Filter: partition too large\n");
91 return RET_REDO;
93 #if DEBUG
94 printf("Filter: partition size: 0x%s / %lu sectors\n",
95 print64(disk_size), sectors);
96 #endif
97 } else {
98 if(cmp64(disk_size, part.size)) {
99 printf("Filter: partition size mismatch (%s != %s)\n",
100 print64(part.size), print64(disk_size));
102 return RET_REDO;
106 return OK;
109 /*===========================================================================*
110 * driver_close *
111 *===========================================================================*/
112 static int driver_close(int which)
114 message msg;
115 int r;
117 msg.m_type = DEV_CLOSE;
118 msg.DEVICE = driver[which].minor;
119 msg.IO_ENDPT = self_ep;
120 r = sendrec(driver[which].endpt, &msg);
122 if (r != OK) {
123 /* Should we restart the driver now? */
124 printf("Filter: driver_close: sendrec returned %d\n", r);
126 return RET_REDO;
129 if(msg.m_type != TASK_REPLY || msg.REP_STATUS != OK) {
130 printf("Filter: driver_close: sendrec returned %d, %d\n",
131 msg.m_type, msg.REP_STATUS);
133 return RET_REDO;
136 return OK;
139 /*===========================================================================*
140 * driver_init *
141 *===========================================================================*/
142 void driver_init(void)
144 /* Initialize the driver layer. */
145 int r;
147 self_ep = getprocnr();
149 memset(driver, 0, sizeof(driver));
151 /* Endpoints unknown. */
152 driver[DRIVER_MAIN].endpt = NONE;
153 driver[DRIVER_BACKUP].endpt = NONE;
155 /* Get disk driver's and this proc's endpoint. */
156 driver[DRIVER_MAIN].label = MAIN_LABEL;
157 driver[DRIVER_MAIN].minor = MAIN_MINOR;
159 r = ds_retrieve_label_num(driver[DRIVER_MAIN].label,
160 (u32_t *) &driver[DRIVER_MAIN].endpt);
161 if (r != OK) {
162 printf("Filter: failed to get main disk driver's endpoint: "
163 "%d\n", r);
164 bad_driver(DRIVER_MAIN, BD_DEAD, EFAULT);
165 check_driver(DRIVER_MAIN);
167 else if (driver_open(DRIVER_MAIN) != OK) {
168 panic(__FILE__, "unhandled driver_open failure", NO_NUM);
171 if(USE_MIRROR) {
172 driver[DRIVER_BACKUP].label = BACKUP_LABEL;
173 driver[DRIVER_BACKUP].minor = BACKUP_MINOR;
175 if(!strcmp(driver[DRIVER_MAIN].label,
176 driver[DRIVER_BACKUP].label)) {
177 panic(__FILE__, "same driver: not tested", NO_NUM);
180 r = ds_retrieve_label_num(driver[DRIVER_BACKUP].label,
181 (u32_t *) &driver[DRIVER_BACKUP].endpt);
182 if (r != OK) {
183 printf("Filter: failed to get backup disk driver's "
184 "endpoint: %d\n", r);
185 bad_driver(DRIVER_BACKUP, BD_DEAD, EFAULT);
186 check_driver(DRIVER_BACKUP);
188 else if (driver_open(DRIVER_BACKUP) != OK) {
189 panic(__FILE__, "unhandled driver_open failure",
190 NO_NUM);
195 /*===========================================================================*
196 * driver_shutdown *
197 *===========================================================================*/
198 void driver_shutdown(void)
200 /* Clean up. */
202 #if DEBUG
203 printf("Filter: %u driver deaths, %u protocol errors, "
204 "%u data errors\n", problem_stats[BD_DEAD],
205 problem_stats[BD_PROTO], problem_stats[BD_DATA]);
206 #endif
208 if(driver_close(DRIVER_MAIN) != OK)
209 printf("Filter: DEV_CLOSE failed on shutdown (1)\n");
211 if(USE_MIRROR)
212 if(driver_close(DRIVER_BACKUP) != OK)
213 printf("Filter: DEV_CLOSE failed on shutdown (2)\n");
216 /*===========================================================================*
217 * get_raw_size *
218 *===========================================================================*/
219 u64_t get_raw_size(void)
221 /* Return the size of the raw disks as used by the filter driver.
224 return disk_size;
227 /*===========================================================================*
228 * reset_kills *
229 *===========================================================================*/
230 void reset_kills(void)
232 /* Reset kill and retry statistics. */
233 driver[DRIVER_MAIN].kills = 0;
234 driver[DRIVER_MAIN].retries = 0;
235 driver[DRIVER_BACKUP].kills = 0;
236 driver[DRIVER_BACKUP].retries = 0;
239 /*===========================================================================*
240 * bad_driver *
241 *===========================================================================*/
242 int bad_driver(int which, int type, int error)
244 /* A disk driver has died or produced an error. Mark it so that we can
245 * deal with it later, and return RET_REDO to indicate that the
246 * current operation is to be retried. Also store an error code to
247 * return to the user if the situation is unrecoverable.
249 driver[which].problem = type;
250 driver[which].error = error;
252 return RET_REDO;
255 /*===========================================================================*
256 * new_driver_ep *
257 *===========================================================================*/
258 static int new_driver_ep(int which)
260 /* See if a new driver instance has already been started for the given
261 * driver, by retrieving its entry from DS.
263 int r;
264 endpoint_t endpt;
266 r = ds_retrieve_label_num(driver[which].label, (u32_t *) &endpt);
268 if (r != OK) {
269 printf("Filter: DS query for %s failed\n",
270 driver[which].label);
272 return 0;
275 if (endpt == driver[which].endpt) {
276 #if DEBUG
277 printf("Filter: same endpoint for %s\n", driver[which].label);
278 #endif
279 return 0;
282 #if DEBUG
283 printf("Filter: new enpdoint for %s: %d -> %d\n", driver[which].label,
284 driver[which].endpt, endpt);
285 #endif
287 driver[which].endpt = endpt;
289 return 1;
292 /*===========================================================================*
293 * check_problem *
294 *===========================================================================*/
295 static int check_problem(int which, int problem, int retries, int *tell_rs)
297 /* A problem has occurred with a driver. Update statistics, and decide
298 * what to do. If EAGAIN is returned, the driver should be restarted;
299 * any other result will be passed up.
302 #if DEBUG
303 printf("Filter: check_driver processing driver %d, problem %d\n",
304 which, problem);
305 #endif
307 problem_stats[problem]++;
309 if(new_driver_ep(which)) {
310 #if DEBUG
311 printf("Filter: check_problem: noticed a new driver\n");
312 #endif
314 if(driver_open(which) == OK) {
315 #if DEBUG2
316 printf("Filter: open OK -> no recovery\n");
317 #endif
318 return OK;
319 } else {
320 #if DEBUG2
321 printf("Filter: open not OK -> recovery\n");
322 #endif
323 problem = BD_PROTO;
324 problem_stats[problem]++;
328 /* If the driver has died, we always need to restart it. If it has
329 * been giving problems, we first retry the request, up to N times,
330 * after which we kill and restart the driver. We restart the driver
331 * up to M times, after which we remove the driver from the mirror
332 * configuration. If we are not set up to do mirroring, we can only
333 * do one thing, and that is continue to limp along with the bad
334 * driver..
336 switch(problem) {
337 case BD_PROTO:
338 case BD_DATA:
339 driver[which].retries++;
341 #if DEBUG
342 printf("Filter: disk driver %d has had "
343 "%d/%d retry attempts, %d/%d kills\n", which,
344 driver[which].retries, NR_RETRIES,
345 driver[which].kills, NR_RESTARTS);
346 #endif
348 if (driver[which].retries < NR_RETRIES) {
349 if(retries == 1) {
350 #if DEBUG
351 printf("Filter: not restarting; retrying "
352 "(retries %d/%d, kills %d/%d)\n",
353 driver[which].retries, NR_RETRIES,
354 driver[which].kills, NR_RESTARTS);
355 #endif
356 return OK;
358 #if DEBUG
359 printf("Filter: restarting (retries %d/%d, "
360 "kills %d/%d, internal retry %d)\n",
361 driver[which].retries, NR_RETRIES,
362 driver[which].kills, NR_RESTARTS, retries);
363 #endif
366 #if DEBUG
367 printf("Filter: disk driver %d has reached error "
368 "threshold, restarting driver\n", which);
369 #endif
371 *tell_rs = 1;
372 break;
374 case BD_DEAD:
375 /* Can't kill that which is already dead.. */
376 *tell_rs = 0;
377 break;
379 default:
380 panic(__FILE__, "invalid problem", problem);
383 /* At this point, the driver will be restarted. */
384 driver[which].retries = 0;
385 driver[which].kills++;
387 if (driver[which].kills < NR_RESTARTS)
388 return EAGAIN;
390 /* We've reached the maximum number of restarts for this driver. */
391 if (USE_MIRROR) {
392 printf("Filter: kill threshold reached, disabling mirroring\n");
394 USE_MIRROR = 0;
396 if (which == DRIVER_MAIN) {
397 driver[DRIVER_MAIN] = driver[DRIVER_BACKUP];
399 /* This is not necessary. */
400 strcpy(MAIN_LABEL, BACKUP_LABEL);
401 MAIN_MINOR = BACKUP_MINOR;
404 driver[DRIVER_BACKUP].endpt = NONE;
406 return OK;
408 else {
409 /* We tried, we really did. But now we give up. Tell the user.
411 printf("Filter: kill threshold reached, returning error\n");
413 if (driver[which].error == EAGAIN) return EIO;
415 return driver[which].error;
419 /*===========================================================================*
420 * restart_driver *
421 *===========================================================================*/
422 static void restart_driver(int which, int tell_rs)
424 /* Restart the given driver. Block until the new instance is up.
426 message msg;
427 endpoint_t endpt;
428 int r, w = 0;
430 if (tell_rs) {
431 /* Tell RS to refresh or restart the driver */
432 msg.m_type = RS_REFRESH;
433 msg.RS_CMD_ADDR = driver[which].label;
434 msg.RS_CMD_LEN = strlen(driver[which].label);
436 #if DEBUG
437 printf("Filter: asking RS to refresh %s..\n",
438 driver[which].label);
439 #endif
441 r = sendrec(RS_PROC_NR, &msg);
443 if (r != OK || msg.m_type != OK)
444 panic(__FILE__, "RS request failed", r);
446 #if DEBUG
447 printf("Filter: RS call succeeded\n");
448 #endif
451 /* Wait until the new driver instance is up, and get its endpoint. */
452 #if DEBUG
453 printf("Filter: endpoint update driver %d; old endpoint %d\n",
454 which, driver[which].endpt);
455 #endif
457 do {
458 if(w) flt_sleep(1);
459 w = 1;
461 r = ds_retrieve_label_num(driver[which].label,
462 (u32_t *) &endpt);
464 #if DEBUG2
465 if (r != OK)
466 printf("Filter: DS request failed (%d)\n", r);
467 else if (endpt == driver[which].endpt)
468 printf("Filter: DS returned same endpoint\n");
469 else
470 printf("Filter: DS request OK, new endpoint\n");
471 #endif
472 } while (r != OK || endpt == driver[which].endpt);
474 driver[which].endpt = endpt;
477 /*===========================================================================*
478 * check_driver *
479 *===========================================================================*/
480 int check_driver(int which)
482 /* See if the given driver has been troublesome, and if so, deal with
483 * it.
485 int problem, tell_rs;
486 int r, retries = 0;
488 problem = driver[which].problem;
490 if (problem == BD_NONE)
491 return OK;
493 do {
494 if(retries) {
495 #if DEBUG
496 printf("Filter: check_driver: retry number %d\n",
497 retries);
498 #endif
499 problem = BD_PROTO;
501 retries++;
502 driver[which].problem = BD_NONE;
504 /* Decide what to do: continue operation, restart the driver,
505 * or return an error.
507 r = check_problem(which, problem, retries, &tell_rs);
508 if (r != EAGAIN)
509 return r;
511 /* Restarting the driver it is. First tell RS (if necessary),
512 * then wait for the new driver instance to come up.
514 restart_driver(which, tell_rs);
516 /* Finally, open the device on the new driver */
517 } while (driver_open(which) != OK);
519 #if DEBUG
520 printf("Filter: check_driver restarted driver %d, endpoint %d\n",
521 which, driver[which].endpt);
522 #endif
524 return OK;
527 /*===========================================================================*
528 * flt_senda *
529 *===========================================================================*/
530 static int flt_senda(message *mess, int which)
532 /* Send a message to one driver. Can only return OK at the moment. */
533 int r;
534 asynmsg_t *amp;
536 /* Fill in the last bits of the message. */
537 mess->DEVICE = driver[which].minor;
538 mess->IO_ENDPT = self_ep;
540 /* Send the message asynchronously. */
541 amp = &amsgtable[which];
542 amp->dst = driver[which].endpt;
543 amp->msg = *mess;
544 amp->flags = AMF_VALID;
545 r = senda(amsgtable, 2);
547 if(r != OK)
548 panic(__FILE__, "senda returned error", r);
550 return r;
553 /*===========================================================================*
554 * check_senda *
555 *===========================================================================*/
556 static int check_senda(int which)
558 /* Check whether an earlier senda resulted in an error indicating the
559 * message never got delivered. Only in that case can we reliably say
560 * that the driver died. Return BD_DEAD in this case, and BD_PROTO
561 * otherwise.
563 asynmsg_t *amp;
565 amp = &amsgtable[which];
567 if ((amp->flags & AMF_DONE) &&
568 (amp->result == EDEADSRCDST || amp->result == EDSTDIED)) {
570 return BD_DEAD;
573 return BD_PROTO;
576 /*===========================================================================*
577 * flt_receive *
578 *===========================================================================*/
579 static int flt_receive(message *mess, int which)
581 /* Receive a message from one or either driver, unless a timeout
582 * occurs. Can only return OK or RET_REDO.
584 int r;
586 for (;;) {
587 r = sef_receive(ANY, mess);
588 if(r != OK)
589 panic(__FILE__, "sef_receive returned error", r);
591 if(mess->m_source == CLOCK && is_notify(mess->m_type)) {
592 if (mess->NOTIFY_TIMESTAMP < flt_alarm(-1)) {
593 #if DEBUG
594 printf("Filter: SKIPPING old alarm "
595 "notification\n");
596 #endif
597 continue;
600 #if DEBUG
601 printf("Filter: timeout waiting for disk driver %d "
602 "reply!\n", which);
603 #endif
605 /* If we're waiting for either driver,
606 * both are at fault.
608 if (which < 0) {
609 bad_driver(DRIVER_MAIN,
610 check_senda(DRIVER_MAIN), EFAULT);
612 return bad_driver(DRIVER_BACKUP,
613 check_senda(DRIVER_BACKUP), EFAULT);
616 /* Otherwise, just report the one not replying as dead.
618 return bad_driver(which, check_senda(which), EFAULT);
621 if (mess->m_source != driver[DRIVER_MAIN].endpt &&
622 mess->m_source != driver[DRIVER_BACKUP].endpt) {
623 #if DEBUG
624 printf("Filter: got STRAY message %d from %d\n",
625 mess->m_type, mess->m_source);
626 #endif
628 continue;
631 /* We are waiting for a reply from one specific driver. */
632 if (which >= 0) {
633 /* If the message source is that driver, good. */
634 if (mess->m_source == driver[which].endpt)
635 break;
637 /* This should probably be treated as a real protocol
638 * error. We do not abort any receives (not even paired
639 * receives) except because of timeouts. Getting here
640 * means a driver replied at least the timeout period
641 * later than expected, which should be enough reason
642 * to kill it really. The other explanation is that it
643 * is actually violating the protocol and sending bogus
644 * messages...
646 #if DEBUG
647 printf("Filter: got UNEXPECTED reply from %d\n",
648 mess->m_source);
649 #endif
651 continue;
654 /* We got a message from one of the drivers, and we didn't
655 * care which one we wanted to receive from. A-OK.
657 break;
660 return OK;
663 /*===========================================================================*
664 * flt_sendrec *
665 *===========================================================================*/
666 static int flt_sendrec(message *mess, int which)
668 int r;
670 r = flt_senda(mess, which);
671 if(r != OK)
672 return r;
674 if(check_senda(which) == BD_DEAD) {
675 return bad_driver(which, BD_DEAD, EFAULT);
678 /* Set alarm. */
679 flt_alarm(DRIVER_TIMEOUT);
681 r = flt_receive(mess, which);
683 /* Clear the alarm. */
684 flt_alarm(0);
685 return r;
688 /*===========================================================================*
689 * do_sendrec_both *
690 *===========================================================================*/
691 static int do_sendrec_both(message *m1, message *m2)
693 /* If USEE_MIRROR is set, call flt_sendrec() to both drivers.
694 * Otherwise, only call flt_sendrec() to the main driver.
695 * This function will only return either OK or RET_REDO.
697 int r, which = -1;
698 message ma, mb;
700 /* If the two disks use the same driver, call flt_sendrec() twice
701 * sequentially. Such a setup is not very useful though.
703 if (!strcmp(driver[DRIVER_MAIN].label, driver[DRIVER_BACKUP].label)) {
704 if ((r = flt_sendrec(m1, DRIVER_MAIN)) != OK) return r;
705 return flt_sendrec(m2, DRIVER_BACKUP);
708 /* If the two disks use different drivers, call flt_senda()
709 * twice, and then flt_receive(), and distinguish the return
710 * messages by means of m_source.
712 if ((r = flt_senda(m1, DRIVER_MAIN)) != OK) return r;
713 if ((r = flt_senda(m2, DRIVER_BACKUP)) != OK) return r;
715 /* Set alarm. */
716 flt_alarm(DRIVER_TIMEOUT);
718 /* The message received by the 1st flt_receive() may not be
719 * from DRIVER_MAIN.
721 if ((r = flt_receive(&ma, -1)) != OK) {
722 flt_alarm(0);
723 return r;
726 if (ma.m_source == driver[DRIVER_MAIN].endpt) {
727 which = DRIVER_BACKUP;
728 } else if (ma.m_source == driver[DRIVER_BACKUP].endpt) {
729 which = DRIVER_MAIN;
730 } else {
731 panic(__FILE__, "message from unexpected source",
732 ma.m_source);
735 r = flt_receive(&mb, which);
737 /* Clear the alarm. */
738 flt_alarm(0);
740 if(r != OK)
741 return r;
743 if (ma.m_source == driver[DRIVER_MAIN].endpt) {
744 *m1 = ma;
745 *m2 = mb;
746 } else {
747 *m1 = mb;
748 *m2 = ma;
751 return OK;
754 /*===========================================================================*
755 * do_sendrec_one *
756 *===========================================================================*/
757 static int do_sendrec_one(message *m1, message *m2)
759 /* Only talk to the main driver. If something goes wrong, it will
760 * be fixed elsewhere.
761 * This function will only return either OK or RET_REDO.
764 return flt_sendrec(m1, DRIVER_MAIN);
767 /*===========================================================================*
768 * paired_sendrec *
769 *===========================================================================*/
770 static int paired_sendrec(message *m1, message *m2, int both)
772 /* Sendrec with the disk driver. If the disk driver is down, and was
773 * restarted, redo the request, until the driver works fine, or can't
774 * be restarted again.
776 int r;
778 #if DEBUG2
779 printf("paired_sendrec(%d) - <%d,%x:%x,%d> - %x,%x\n",
780 both, m1->m_type, m1->HIGHPOS, m1->POSITION, m1->COUNT,
781 m1->IO_GRANT, m2->IO_GRANT);
782 #endif
784 if (both)
785 r = do_sendrec_both(m1, m2);
786 else
787 r = do_sendrec_one(m1, m2);
789 #if DEBUG2
790 if (r != OK)
791 printf("paired_sendrec about to return %d\n", r);
792 #endif
794 return r;
797 /*===========================================================================*
798 * single_grant *
799 *===========================================================================*/
800 static int single_grant(endpoint_t endpt, vir_bytes buf, int access,
801 cp_grant_id_t *gid, iovec_s_t vector[NR_IOREQS], size_t *sizep)
803 /* Create grants for a vectored request to a single driver.
805 cp_grant_id_t grant;
806 size_t size, chunk;
807 int count;
809 size = *sizep;
811 /* Split up the request into chunks, if requested. This makes no
812 * difference at all, except that this works around a weird performance
813 * bug with large DMA PRDs on some machines.
815 if (CHUNK_SIZE > 0) chunk = CHUNK_SIZE;
816 else chunk = size;
818 /* Fill in the vector, creating a grant for each item. */
819 for (count = 0; size > 0 && count < NR_IOREQS; count++) {
820 /* The last chunk will contain all the remaining data. */
821 if (chunk > size || count == NR_IOREQS - 1)
822 chunk = size;
824 grant = cpf_grant_direct(endpt, buf, chunk, access);
825 if (!GRANT_VALID(grant))
826 panic(__FILE__, "invalid grant", grant);
828 vector[count].iov_grant = grant;
829 vector[count].iov_size = chunk;
831 buf += chunk;
832 size -= chunk;
835 /* Then create a grant for the vector itself. */
836 *gid = cpf_grant_direct(endpt, (vir_bytes) vector,
837 sizeof(vector[0]) * count, CPF_READ | CPF_WRITE);
839 if (!GRANT_VALID(*gid))
840 panic(__FILE__, "invalid grant", *gid);
842 return count;
845 /*===========================================================================*
846 * paired_grant *
847 *===========================================================================*/
848 static int paired_grant(char *buf1, char *buf2, int request,
849 cp_grant_id_t *gids, iovec_s_t vectors[2][NR_IOREQS], size_t *sizes,
850 int both)
852 /* Create memory grants, either to one or to both drivers.
854 int count, access;
856 count = 0;
857 access = (request == FLT_WRITE) ? CPF_READ : CPF_WRITE;
859 if(driver[DRIVER_MAIN].endpt > 0) {
860 count = single_grant(driver[DRIVER_MAIN].endpt,
861 (vir_bytes) buf1, access, &gids[0], vectors[0],
862 &sizes[0]);
865 if (both) {
866 if(driver[DRIVER_BACKUP].endpt > 0) {
867 count = single_grant(driver[DRIVER_BACKUP].endpt,
868 (vir_bytes) buf2, access, &gids[1],
869 vectors[1], &sizes[1]);
872 return count;
875 /*===========================================================================*
876 * single_revoke *
877 *===========================================================================*/
878 PRIVATE void single_revoke(cp_grant_id_t gid, iovec_s_t vector[NR_IOREQS],
879 size_t *sizep, int count)
881 /* Revoke all grants associated with a request to a single driver.
882 * Modify the given size to reflect the actual I/O performed.
884 int i;
886 /* Revoke the grants for all the elements of the vector. */
887 for (i = 0; i < count; i++) {
888 cpf_revoke(vector[i].iov_grant);
889 *sizep -= vector[i].iov_size;
892 /* Then revoke the grant for the vector itself. */
893 cpf_revoke(gid);
896 /*===========================================================================*
897 * paired_revoke *
898 *===========================================================================*/
899 static void paired_revoke(cp_grant_id_t *gids, iovec_s_t vectors[2][NR_IOREQS],
900 size_t *sizes, int count, int both)
902 /* Revoke grants to drivers for a single request.
905 single_revoke(gids[0], vectors[0], &sizes[0], count);
907 if (both)
908 single_revoke(gids[1], vectors[1], &sizes[1], count);
911 /*===========================================================================*
912 * read_write *
913 *===========================================================================*/
914 int read_write(u64_t pos, char *bufa, char *bufb, size_t *sizep, int request)
916 iovec_s_t vectors[2][NR_IOREQS];
917 message m1, m2;
918 cp_grant_id_t gids[2];
919 size_t sizes[2];
920 int r, both, count;
922 gids[0] = gids[1] = GRANT_INVALID;
923 sizes[0] = sizes[1] = *sizep;
925 /* Send two requests only if mirroring is enabled and the given request
926 * is either FLT_READ2 or FLT_WRITE.
928 both = (USE_MIRROR && request != FLT_READ);
930 count = paired_grant(bufa, bufb, request, gids, vectors, sizes, both);
932 m1.m_type = (request == FLT_WRITE) ? DEV_SCATTER_S : DEV_GATHER_S;
933 m1.COUNT = count;
934 m1.POSITION = ex64lo(pos);
935 m1.HIGHPOS = ex64hi(pos);
937 m2 = m1;
939 m1.IO_GRANT = (char *) gids[0];
940 m2.IO_GRANT = (char *) gids[1];
942 r = paired_sendrec(&m1, &m2, both);
944 paired_revoke(gids, vectors, sizes, count, both);
946 if(r != OK) {
947 #if DEBUG
948 if (r != RET_REDO)
949 printf("Filter: paired_sendrec returned %d\n", r);
950 #endif
951 return r;
954 if (m1.m_type != TASK_REPLY || m1.REP_STATUS != OK) {
955 printf("Filter: unexpected/invalid reply from main driver: "
956 "(%x, %d)\n", m1.m_type, m1.REP_STATUS);
958 return bad_driver(DRIVER_MAIN, BD_PROTO,
959 (m1.m_type == TASK_REPLY) ? m1.REP_STATUS : EFAULT);
962 if (sizes[0] != *sizep) {
963 printf("Filter: truncated reply from main driver\n");
965 /* If the driver returned a value *larger* than we requested,
966 * OR if we did NOT exceed the disk size, then we should
967 * report the driver for acting strangely!
969 if (sizes[0] < 0 || sizes[0] > *sizep ||
970 cmp64(add64u(pos, sizes[0]), disk_size) < 0)
971 return bad_driver(DRIVER_MAIN, BD_PROTO, EFAULT);
973 /* Return the actual size. */
974 *sizep = sizes[0];
977 if (both) {
978 if (m2.m_type != TASK_REPLY || m2.REP_STATUS != OK) {
979 printf("Filter: unexpected/invalid reply from "
980 "backup driver (%x, %d)\n",
981 m2.m_type, m2.REP_STATUS);
983 return bad_driver(DRIVER_BACKUP, BD_PROTO,
984 m2.m_type == TASK_REPLY ? m2.REP_STATUS :
985 EFAULT);
987 if (sizes[1] != *sizep) {
988 printf("Filter: truncated reply from backup driver\n");
990 /* As above */
991 if (sizes[1] < 0 || sizes[1] > *sizep ||
992 cmp64(add64u(pos, sizes[1]), disk_size) < 0)
993 return bad_driver(DRIVER_BACKUP, BD_PROTO,
994 EFAULT);
996 /* Return the actual size. */
997 if (*sizep >= sizes[1])
998 *sizep = sizes[1];
1002 return OK;