xref: /minix/minix/servers/vfs/smap.c (revision 27852ebe)
1 /*
2  * This file contains the table with socket driver mappings.  One socket driver
3  * may implement multiple domains (e.g., PF_INET and PF_INET6).  For this
4  * reason, we assign a unique number to each socket driver, and use a "socket
5  * device map" table (smap) that maps from those numbers to information about
6  * socket drivers.  This number is combined with a per-driver socket identifier
7  * to form a globally unique socket ID (64-bit, stored as dev_t).  In addition,
8  * we use a table that maps from PF_xxx domains to socket drivers (pfmap).
9  */
10 
11 #include "fs.h"
12 #include <sys/socket.h>
13 #include <assert.h>
14 
15 static struct smap smap[NR_SOCKDEVS];
16 static struct smap *pfmap[PF_MAX];
17 
18 /*
19  * Initialize the socket device map table.
20  */
21 void
22 init_smap(void)
23 {
24 	unsigned int i;
25 
26 	for (i = 0; i < __arraycount(smap); i++) {
27 		/*
28 		 * The smap numbers are one-based so as to ensure that no
29 		 * socket will have the device number NO_DEV, which would
30 		 * create problems with eg the select code.
31 		 */
32 		smap[i].smap_num = i + 1;
33 		smap[i].smap_endpt = NONE;
34 	}
35 
36 	memset(pfmap, 0, sizeof(pfmap));
37 }
38 
39 /*
40  * Register a socket driver.  This action can only be requested by RS.  The
41  * process identified by the given DS label 'label' and endpoint 'endpt' is to
42  * be responsible for sockets created in the domains as given in the 'domains'
43  * array, which contains 'ndomains' elements.  Return OK upon successful
44  * registration, or an error code otherwise.
45  */
46 int
47 smap_map(const char * label, endpoint_t endpt, const int * domains,
48 	unsigned int ndomains)
49 {
50 	struct smap *sp;
51 	unsigned int i, num = 0;
52 	int domain;
53 
54 	if (ndomains <= 0 || ndomains > NR_DOMAIN)
55 		return EINVAL;
56 
57 	/*
58 	 * See if there is already a socket device map entry for this label.
59 	 * If so, the socket driver is probably being restarted, and we should
60 	 * overwrite its previous entry.
61 	 */
62 	sp = NULL;
63 	for (i = 0; i < __arraycount(smap); i++) {
64 		if (smap[i].smap_endpt != NONE &&
65 		    !strcmp(smap[i].smap_label, label)) {
66 			sp = &smap[i];
67 			break;
68 		}
69 	}
70 
71 	/*
72 	 * See if all given domains are valid and not already reserved by a
73 	 * socket driver other than (if applicable) this driver's old instance.
74 	 */
75 	for (i = 0; i < ndomains; i++) {
76 		domain = domains[i];
77 		if (domain < 0 || domain >= __arraycount(pfmap))
78 			return EINVAL;
79 		if (domain == PF_UNSPEC)
80 			return EINVAL;
81 		if (pfmap[domain] != NULL && pfmap[domain] != sp)
82 			return EBUSY;
83 	}
84 
85 	/*
86 	 * If we are not about to replace an existing socket device map entry,
87 	 * find a free entry, returning an error if all entries are in use.
88 	 */
89 	if (sp == NULL) {
90 		for (num = 0; num < __arraycount(smap); num++)
91 			if (smap[num].smap_endpt == NONE)
92 				break;
93 
94 		if (num == __arraycount(smap))
95 			return ENOMEM;
96 	} else
97 		num = (unsigned int)(sp - smap);
98 
99 	/*
100 	 * At this point, the registration will succeed, and we can start
101 	 * modifying tables.  Just to be sure, unmap the domain mappings for
102 	 * the old instance, in case it is somehow registered with a different
103 	 * set of domains.  Also, if the endpoint of the service has changed,
104 	 * cancel any operations involving the previous endpoint and invalidate
105 	 * any preexisting sockets.  However, for stateful restarts where the
106 	 * service endpoint does not change, leave things as is.
107 	 */
108 	if (sp != NULL) {
109 		if (sp->smap_endpt != endpt) {
110 			/*
111 			 * For stateless restarts, it is common that the new
112 			 * endpoint is made ready before the old endpoint is
113 			 * exited, so we cannot wait for the exit handling code
114 			 * to do these steps, as they rely on the old socket
115 			 * mapping still being around.
116 			 */
117 			unsuspend_by_endpt(sp->smap_endpt);
118 
119 			invalidate_filp_by_sock_drv(sp->smap_num);
120 		}
121 
122 		for (i = 0; i < __arraycount(pfmap); i++)
123 			if (pfmap[i] == sp)
124 				pfmap[i] = NULL;
125 	}
126 
127 	/*
128 	 * Initialize the socket driver map entry, and set up the domain map
129 	 * entries.
130 	 */
131 	sp = &smap[num];
132 	sp->smap_endpt = endpt;
133 	strlcpy(sp->smap_label, label, sizeof(sp->smap_label));
134 	sp->smap_sel_busy = FALSE;
135 	sp->smap_sel_filp = NULL;
136 
137 	for (i = 0; i < ndomains; i++)
138 		pfmap[domains[i]] = sp;
139 
140 	return OK;
141 }
142 
143 /*
144  * The process with the given endpoint has exited.  If the endpoint identifies
145  * a socket driver, deregister the driver and invalidate any sockets it owned.
146  */
147 void
148 smap_unmap_by_endpt(endpoint_t endpt)
149 {
150 	struct smap *sp;
151 	unsigned int i;
152 
153 	if ((sp = get_smap_by_endpt(endpt)) == NULL)
154 		return;
155 
156 	/*
157 	 * Invalidation requires that the smap entry still be around, so do
158 	 * this before clearing the endpoint.
159 	 */
160 	invalidate_filp_by_sock_drv(sp->smap_num);
161 
162 	sp->smap_endpt = NONE;
163 
164 	for (i = 0; i < __arraycount(pfmap); i++)
165 		if (pfmap[i] == sp)
166 			pfmap[i] = NULL;
167 }
168 
169 /*
170  * The given endpoint has announced itself as a socket driver.
171  */
172 void
173 smap_endpt_up(endpoint_t endpt)
174 {
175 	struct smap *sp;
176 
177 	if ((sp = get_smap_by_endpt(endpt)) == NULL)
178 		return;
179 
180 	/*
181 	 * The announcement indicates that the socket driver has either started
182 	 * anew or restarted statelessly.  In the second case, none of its
183 	 * previously existing sockets will have survived, so mark them as
184 	 * invalid.
185 	 */
186 	invalidate_filp_by_sock_drv(sp->smap_num);
187 }
188 
189 /*
190  * Construct a device number that combines the entry number of the given socket
191  * map and the given per-driver socket identifier, thus constructing a unique
192  * identifier for the socket.  Generally speaking, we use the dev_t type
193  * because the value is stored as special device number (sdev) on a socket node
194  * on PFS.  We use our own bit division rather than the standard major/minor
195  * division because this simplifies using each half as a 32-bit value.  The
196  * block/character device numbers and socket device numbers are in different
197  * namespaces, and numbers may overlap (even though this is currently
198  * practically impossible), so one must always test the file type first.
199  */
200 dev_t
201 make_smap_dev(struct smap * sp, sockid_t sockid)
202 {
203 
204 	assert(sp->smap_endpt != NONE);
205 	assert(sockid >= 0);
206 
207 	return (dev_t)(((uint64_t)sp->smap_num << 32) | (uint32_t)sockid);
208 }
209 
210 /*
211  * Return a pointer to the smap structure for the socket driver associated with
212  * the socket device number.  In addition, if the given socket ID pointer is
213  * not NULL, store the per-driver socket identifier in it.  Return NULL if the
214  * given socket device number is not a socket for a valid socket driver.
215  */
216 struct smap *
217 get_smap_by_dev(dev_t dev, sockid_t * sockidp)
218 {
219 	struct smap *sp;
220 	unsigned int num;
221 	sockid_t id;
222 
223 	num = (unsigned int)(dev >> 32);
224 	id = (sockid_t)(dev & ((1ULL << 32) - 1));
225 	if (num == 0 || num > __arraycount(smap) || id < 0)
226 		return NULL;
227 
228 	sp = &smap[num - 1];
229 	assert(sp->smap_num == num);
230 
231 	if (sp->smap_endpt == NONE)
232 		return NULL;
233 
234 	if (sockidp != NULL)
235 		*sockidp = id;
236 	return sp;
237 }
238 
239 /*
240  * Return a pointer to the smap structure for the socket driver with the given
241  * endpoint.  Return NULL if the endpoint does not identify a socket driver.
242  */
243 struct smap *
244 get_smap_by_endpt(endpoint_t endpt)
245 {
246 	unsigned int i;
247 
248 	/*
249 	 * TODO: this function is used rather frequently, so it would be nice
250 	 * to get rid of the O(n) loop here.  The get_dmap_by_endpt() function
251 	 * suffers from the same problem.  It might be worth adding an extra
252 	 * field to the fproc structure for this.
253 	 */
254 	for (i = 0; i < __arraycount(smap); i++)
255 		if (smap[i].smap_endpt == endpt)
256 			return &smap[i];
257 
258 	return NULL;
259 }
260 
261 /*
262  * Return a pointer to the smap structure for the socket driver handling the
263  * given domain (protocol family).  Return NULL if there is no match.
264  */
265 struct smap *
266 get_smap_by_domain(int domain)
267 {
268 
269 	if (domain < 0 || domain >= __arraycount(pfmap))
270 		return NULL;
271 
272 	return pfmap[domain]; /* may be NULL */
273 }
274