libbdev: extended version
This version of libbdev support asynchronous communication, recovery after driver restarts, and retrying of failed transfer operations.
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
/* libbdev - tracking and reopening of opened minor devices */
|
||||
|
||||
#include <minix/drivers.h>
|
||||
#include <minix/bdev.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "const.h"
|
||||
#include "type.h"
|
||||
#include "proto.h"
|
||||
|
||||
static struct {
|
||||
dev_t dev;
|
||||
int count;
|
||||
int access;
|
||||
} open_dev[NR_OPEN_DEVS] = { { NO_DEV, 0, 0 } };
|
||||
|
||||
int bdev_minor_reopen(dev_t dev)
|
||||
{
|
||||
/* Reopen all minor devices on a major device. This function duplicates some
|
||||
* code from elsewhere, because in this case we must avoid performing recovery.
|
||||
* FIXME: if reopening fails with a non-IPC error, we should attempt to close
|
||||
* all minors that we did manage to reopen so far, or they might stay open
|
||||
* forever.
|
||||
*/
|
||||
endpoint_t endpt;
|
||||
message m;
|
||||
int i, j, r, major;
|
||||
|
||||
major = major(dev);
|
||||
endpt = bdev_driver_get(dev);
|
||||
|
||||
assert(endpt != NONE);
|
||||
|
||||
for (i = 0; i < NR_OPEN_DEVS; i++) {
|
||||
if (major(open_dev[i].dev) != major)
|
||||
continue;
|
||||
|
||||
/* Each minor device may have been opened multiple times. Send an open
|
||||
* request for each time that it was opened before. We could reopen it
|
||||
* just once, but then we'd have to keep a shadow open count as well.
|
||||
*/
|
||||
for (j = 0; j < open_dev[i].count; j++) {
|
||||
memset(&m, 0, sizeof(m));
|
||||
m.m_type = BDEV_OPEN;
|
||||
m.BDEV_MINOR = minor(open_dev[i].dev);
|
||||
m.BDEV_ACCESS = open_dev[i].access;
|
||||
m.BDEV_ID = NO_ID;
|
||||
|
||||
if ((r = sendrec(endpt, &m)) != OK) {
|
||||
printf("bdev: IPC to driver (%d) failed (%d)\n",
|
||||
endpt, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
if (m.m_type != BDEV_REPLY) {
|
||||
printf("bdev: driver (%d) sent weird response (%d)\n",
|
||||
endpt, m.m_type);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (m.BDEV_ID != NO_ID) {
|
||||
printf("bdev: driver (%d) sent invalid ID (%ld)\n",
|
||||
endpt, m.BDEV_ID);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if ((r = m.BDEV_STATUS) != OK) {
|
||||
printf("bdev: driver (%d) failed device reopen (%d)\n",
|
||||
endpt, r);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
void bdev_minor_add(dev_t dev, int access)
|
||||
{
|
||||
/* Increase the reference count of the given minor device.
|
||||
*/
|
||||
int i, free = -1;
|
||||
|
||||
for (i = 0; i < NR_OPEN_DEVS; i++) {
|
||||
if (open_dev[i].dev == dev) {
|
||||
open_dev[i].count++;
|
||||
open_dev[i].access |= access;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (free < 0 && open_dev[i].dev == NO_DEV)
|
||||
free = i;
|
||||
}
|
||||
|
||||
if (free < 0) {
|
||||
printf("bdev: too many open devices, increase NR_OPEN_DEVS\n");
|
||||
return;
|
||||
}
|
||||
|
||||
open_dev[free].dev = dev;
|
||||
open_dev[free].count = 1;
|
||||
open_dev[free].access = access;
|
||||
}
|
||||
|
||||
void bdev_minor_del(dev_t dev)
|
||||
{
|
||||
/* Decrease the reference count of the given minor device, if present.
|
||||
*/
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NR_OPEN_DEVS; i++) {
|
||||
if (open_dev[i].dev == dev) {
|
||||
if (!--open_dev[i].count)
|
||||
open_dev[i].dev = NO_DEV;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user