1 /* libbdev - tracking and reopening of opened minor devices */
2
3 #include <minix/drivers.h>
4 #include <minix/bdev.h>
5 #include <assert.h>
6
7 #include "const.h"
8 #include "type.h"
9 #include "proto.h"
10
11 static struct {
12 dev_t dev;
13 int count;
14 int access;
15 } open_dev[NR_OPEN_DEVS] = { { NO_DEV, 0, 0 } };
16
bdev_minor_reopen(dev_t dev)17 int bdev_minor_reopen(dev_t dev)
18 {
19 /* Reopen all minor devices on a major device. This function duplicates some
20 * code from elsewhere, because in this case we must avoid performing recovery.
21 * FIXME: if reopening fails with a non-IPC error, we should attempt to close
22 * all minors that we did manage to reopen so far, or they might stay open
23 * forever.
24 */
25 endpoint_t endpt;
26 message m;
27 int i, j, r, major;
28
29 major = major(dev);
30 endpt = bdev_driver_get(dev);
31
32 assert(endpt != NONE);
33
34 for (i = 0; i < NR_OPEN_DEVS; i++) {
35 if (major(open_dev[i].dev) != major)
36 continue;
37
38 /* Each minor device may have been opened multiple times. Send an open
39 * request for each time that it was opened before. We could reopen it
40 * just once, but then we'd have to keep a shadow open count as well.
41 */
42 for (j = 0; j < open_dev[i].count; j++) {
43 memset(&m, 0, sizeof(m));
44 m.m_type = BDEV_OPEN;
45 m.m_lbdev_lblockdriver_msg.minor = minor(open_dev[i].dev);
46 m.m_lbdev_lblockdriver_msg.access = open_dev[i].access;
47 m.m_lbdev_lblockdriver_msg.id = NO_ID;
48
49 if ((r = ipc_sendrec(endpt, &m)) != OK) {
50 printf("bdev: IPC to driver (%d) failed (%d)\n",
51 endpt, r);
52 return r;
53 }
54
55 if (m.m_type != BDEV_REPLY) {
56 printf("bdev: driver (%d) sent weird response (%d)\n",
57 endpt, m.m_type);
58 return EINVAL;
59 }
60
61 if (m.m_lblockdriver_lbdev_reply.id != NO_ID) {
62 printf("bdev: driver (%d) sent invalid ID (%d)\n",
63 endpt, m.m_lblockdriver_lbdev_reply.id);
64 return EINVAL;
65 }
66
67 if ((r = m.m_lblockdriver_lbdev_reply.status) != OK) {
68 printf("bdev: driver (%d) failed device reopen (%d)\n",
69 endpt, r);
70 return r;
71 }
72 }
73 }
74
75 return OK;
76 }
77
bdev_minor_add(dev_t dev,int bits)78 void bdev_minor_add(dev_t dev, int bits)
79 {
80 /* Increase the reference count of the given minor device.
81 */
82 int i, ifree = -1;
83
84 for (i = 0; i < NR_OPEN_DEVS; i++) {
85 if (open_dev[i].dev == dev) {
86 open_dev[i].count++;
87 open_dev[i].access |= bits;
88
89 return;
90 }
91
92 if (ifree < 0 && open_dev[i].dev == NO_DEV)
93 ifree = i;
94 }
95
96 if (ifree < 0) {
97 printf("bdev: too many open devices, increase NR_OPEN_DEVS\n");
98 return;
99 }
100
101 open_dev[ifree].dev = dev;
102 open_dev[ifree].count = 1;
103 open_dev[ifree].access = bits;
104 }
105
bdev_minor_del(dev_t dev)106 void bdev_minor_del(dev_t dev)
107 {
108 /* Decrease the reference count of the given minor device, if present.
109 */
110 int i;
111
112 for (i = 0; i < NR_OPEN_DEVS; i++) {
113 if (open_dev[i].dev == dev) {
114 if (!--open_dev[i].count)
115 open_dev[i].dev = NO_DEV;
116
117 break;
118 }
119 }
120 }
121
bdev_minor_is_open(dev_t dev)122 int bdev_minor_is_open(dev_t dev)
123 {
124 /* Return whether any minor is open for the major of the given device.
125 */
126 int i, major;
127
128 major = major(dev);
129
130 for (i = 0; i < NR_OPEN_DEVS; i++) {
131 if (major(open_dev[i].dev) == major)
132 return TRUE;
133 }
134
135 return FALSE;
136 }
137