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).
12 #include <sys/socket.h>
15 static struct smap smap
[NR_SOCKDEVS
];
16 static struct smap
*pfmap
[PF_MAX
];
19 * Initialize the socket device map table.
26 for (i
= 0; i
< __arraycount(smap
); i
++) {
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.
32 smap
[i
].smap_num
= i
+ 1;
33 smap
[i
].smap_endpt
= NONE
;
36 memset(pfmap
, 0, sizeof(pfmap
));
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.
47 smap_map(const char * label
, endpoint_t endpt
, const int * domains
,
48 unsigned int ndomains
)
51 unsigned int i
, num
= 0;
54 if (ndomains
<= 0 || ndomains
> NR_DOMAIN
)
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.
63 for (i
= 0; i
< __arraycount(smap
); i
++) {
64 if (smap
[i
].smap_endpt
!= NONE
&&
65 !strcmp(smap
[i
].smap_label
, label
)) {
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.
75 for (i
= 0; i
< ndomains
; i
++) {
77 if (domain
< 0 || domain
>= __arraycount(pfmap
))
79 if (domain
== PF_UNSPEC
)
81 if (pfmap
[domain
] != NULL
&& pfmap
[domain
] != sp
)
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.
90 for (num
= 0; num
< __arraycount(smap
); num
++)
91 if (smap
[num
].smap_endpt
== NONE
)
94 if (num
== __arraycount(smap
))
97 num
= (unsigned int)(sp
- smap
);
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.
109 if (sp
->smap_endpt
!= endpt
) {
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.
117 unsuspend_by_endpt(sp
->smap_endpt
);
119 invalidate_filp_by_sock_drv(sp
->smap_num
);
122 for (i
= 0; i
< __arraycount(pfmap
); i
++)
128 * Initialize the socket driver map entry, and set up the domain map
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
;
137 for (i
= 0; i
< ndomains
; i
++)
138 pfmap
[domains
[i
]] = sp
;
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.
148 smap_unmap_by_endpt(endpoint_t endpt
)
153 if ((sp
= get_smap_by_endpt(endpt
)) == NULL
)
157 * Invalidation requires that the smap entry still be around, so do
158 * this before clearing the endpoint.
160 invalidate_filp_by_sock_drv(sp
->smap_num
);
162 sp
->smap_endpt
= NONE
;
164 for (i
= 0; i
< __arraycount(pfmap
); i
++)
170 * The given endpoint has announced itself as a socket driver.
173 smap_endpt_up(endpoint_t endpt
)
177 if ((sp
= get_smap_by_endpt(endpt
)) == NULL
)
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
186 invalidate_filp_by_sock_drv(sp
->smap_num
);
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.
201 make_smap_dev(struct smap
* sp
, sockid_t sockid
)
204 assert(sp
->smap_endpt
!= NONE
);
207 return (dev_t
)(((uint64_t)sp
->smap_num
<< 32) | (uint32_t)sockid
);
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.
217 get_smap_by_dev(dev_t dev
, sockid_t
* sockidp
)
223 num
= (unsigned int)(dev
>> 32);
224 id
= (sockid_t
)(dev
& ((1ULL << 32) - 1));
225 if (num
== 0 || num
> __arraycount(smap
) || id
< 0)
229 assert(sp
->smap_num
== num
);
231 if (sp
->smap_endpt
== NONE
)
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.
244 get_smap_by_endpt(endpoint_t endpt
)
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.
254 for (i
= 0; i
< __arraycount(smap
); i
++)
255 if (smap
[i
].smap_endpt
== endpt
)
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.
266 get_smap_by_domain(int domain
)
269 if (domain
< 0 || domain
>= __arraycount(pfmap
))
272 return pfmap
[domain
]; /* may be NULL */