minix/minix/lib/libbdev/minor.c
David van Moolenbroek 7c48de6cc4 Resolve more warnings
Change-Id: Ibc1b7f7cd45ad7295285e59c6ce55888266fece8
2015-09-23 12:04:58 +00:00

137 lines
3 KiB
C

/* 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.m_lbdev_lblockdriver_msg.minor = minor(open_dev[i].dev);
m.m_lbdev_lblockdriver_msg.access = open_dev[i].access;
m.m_lbdev_lblockdriver_msg.id = NO_ID;
if ((r = ipc_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.m_lblockdriver_lbdev_reply.id != NO_ID) {
printf("bdev: driver (%d) sent invalid ID (%d)\n",
endpt, m.m_lblockdriver_lbdev_reply.id);
return EINVAL;
}
if ((r = m.m_lblockdriver_lbdev_reply.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 bits)
{
/* Increase the reference count of the given minor device.
*/
int i, ifree = -1;
for (i = 0; i < NR_OPEN_DEVS; i++) {
if (open_dev[i].dev == dev) {
open_dev[i].count++;
open_dev[i].access |= bits;
return;
}
if (ifree < 0 && open_dev[i].dev == NO_DEV)
ifree = i;
}
if (ifree < 0) {
printf("bdev: too many open devices, increase NR_OPEN_DEVS\n");
return;
}
open_dev[ifree].dev = dev;
open_dev[ifree].count = 1;
open_dev[ifree].access = bits;
}
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;
}
}
}
int bdev_minor_is_open(dev_t dev)
{
/* Return whether any minor is open for the major of the given device.
*/
int i, major;
major = major(dev);
for (i = 0; i < NR_OPEN_DEVS; i++) {
if (major(open_dev[i].dev) == major)
return TRUE;
}
return FALSE;
}