xref: /minix/minix/lib/libbdev/minor.c (revision 0a6a1f1d)
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 
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 
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 
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 
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