make vfs & filesystems use failable copying
[minix3.git] / lib / libsys / safecopies.c
blob3cce51b4803994c57eca9f18714162630df69795
2 /* Library functions to maintain internal data copying tables.
4 * April 21 2006: Initial version (Ben Gras)
6 */
8 #include <lib.h>
9 #include <errno.h>
10 #include <minix/sysutil.h>
11 #include <assert.h>
12 #include <stdlib.h>
13 #include <minix/syslib.h>
14 #include <minix/safecopies.h>
15 #include <minix/com.h>
16 #include <string.h>
18 #define ACCESS_CHECK(a) { \
19 if((a) & ~(CPF_READ|CPF_WRITE|CPF_TRY)) { \
20 errno = EINVAL; \
21 return -1; \
22 } \
25 #define GID_CHECK(gid) { \
26 if(!GRANT_VALID(gid) || (gid) < 0 || (gid) >= ngrants) {\
27 errno = EINVAL; \
28 return -1; \
29 } \
32 #define GID_CHECK_USED(gid) { \
33 GID_CHECK(gid); \
34 if(!(grants[gid].cp_flags & CPF_USED)) { \
35 errno = EINVAL; \
36 return -1; \
37 } \
40 #define CLICK_ALIGNMENT_CHECK(addr, bytes) { \
41 if(((vir_bytes)(addr) % CLICK_SIZE != 0) \
42 || ((vir_bytes)(bytes) % CLICK_SIZE != 0)) { \
43 return EINVAL; \
44 } \
47 #define NR_STATIC_GRANTS 2
48 static cp_grant_t static_grants[NR_STATIC_GRANTS];
49 static cp_grant_t *grants = NULL;
50 static int ngrants = 0;
52 static void
53 cpf_grow(void)
55 /* Grow the grants table if possible. */
56 cp_grant_t *new_grants;
57 cp_grant_id_t g;
58 int new_size;
60 if(!ngrants) {
61 /* Use statically allocated grants the first time. */
62 new_size = NR_STATIC_GRANTS;
63 new_grants = static_grants;
65 else {
66 new_size = (1+ngrants)*2;
67 assert(new_size > ngrants);
69 /* Allocate a block of new size. */
70 if(!(new_grants=malloc(new_size * sizeof(grants[0])))) {
71 return;
75 /* Copy old block to new block. */
76 if(grants && ngrants > 0)
77 memcpy(new_grants, grants, ngrants * sizeof(grants[0]));
79 /* Make sure new slots are marked unused (CPF_USED is clear). */
80 for(g = ngrants; g < new_size; g++)
81 new_grants[g].cp_flags = 0;
83 /* Inform kernel about new size (and possibly new location). */
84 if((sys_setgrant(new_grants, new_size))) {
85 if(new_grants != static_grants) free(new_grants);
86 return; /* Failed - don't grow then. */
89 /* Update internal data. */
90 if(grants && ngrants > 0 && grants != static_grants) free(grants);
91 grants = new_grants;
92 ngrants = new_size;
95 static cp_grant_id_t
96 cpf_new_grantslot(void)
98 /* Find a new, free grant slot in the grant table, grow it if
99 * necessary. If no free slot is found and the grow failed,
100 * return -1. Otherwise, return grant slot number.
102 cp_grant_id_t g;
104 /* Find free slot. */
105 for(g = 0; g < ngrants && (grants[g].cp_flags & CPF_USED); g++)
108 assert(g <= ngrants);
110 /* No free slot found? */
111 if(g == ngrants) {
112 cpf_grow();
113 assert(g <= ngrants); /* ngrants can't shrink. */
114 if(g == ngrants) {
115 /* ngrants hasn't increased. */
116 errno = ENOSPC;
117 return -1;
121 /* Basic sanity checks - if we get this far, g must be a valid,
122 * free slot.
124 assert(GRANT_VALID(g));
125 assert(g >= 0);
126 assert(g < ngrants);
127 assert(!(grants[g].cp_flags & CPF_USED));
129 return g;
132 cp_grant_id_t
133 cpf_grant_direct(endpoint_t who_to, vir_bytes addr, size_t bytes, int access)
135 cp_grant_id_t g;
136 int r;
138 /* Get new slot to put new grant in. */
139 if((g = cpf_new_grantslot()) < 0)
140 return(GRANT_INVALID);
142 assert(GRANT_VALID(g));
143 assert(g >= 0);
144 assert(g < ngrants);
145 assert(!(grants[g].cp_flags & CPF_USED));
147 if((r=cpf_setgrant_direct(g, who_to, addr, bytes, access)) < 0) {
148 cpf_revoke(g);
149 return(GRANT_INVALID);
152 return g;
155 cp_grant_id_t
156 cpf_grant_indirect(endpoint_t who_to, endpoint_t who_from, cp_grant_id_t gr)
158 /* Grant process A access into process B. B has granted us access as grant
159 * id 'gr'.
161 cp_grant_id_t g;
162 int r;
164 /* Obtain new slot. */
165 if((g = cpf_new_grantslot()) < 0)
166 return -1;
168 /* Basic sanity checks. */
169 assert(GRANT_VALID(g));
170 assert(g >= 0);
171 assert(g < ngrants);
172 assert(!(grants[g].cp_flags & CPF_USED));
174 /* Fill in new slot data. */
175 if((r=cpf_setgrant_indirect(g, who_to, who_from, gr)) < 0) {
176 cpf_revoke(g);
177 return GRANT_INVALID;
180 return g;
183 cp_grant_id_t
184 cpf_grant_magic(endpoint_t who_to, endpoint_t who_from,
185 vir_bytes addr, size_t bytes, int access)
187 /* Grant process A access into process B. Not everyone can do this. */
188 cp_grant_id_t g;
189 int r;
191 ACCESS_CHECK(access);
193 /* Obtain new slot. */
194 if((g = cpf_new_grantslot()) < 0)
195 return -1;
197 /* Basic sanity checks. */
198 assert(GRANT_VALID(g));
199 assert(g >= 0);
200 assert(g < ngrants);
201 assert(!(grants[g].cp_flags & CPF_USED));
203 if((r=cpf_setgrant_magic(g, who_to, who_from, addr,
204 bytes, access)) < 0) {
205 cpf_revoke(g);
206 return -1;
209 return g;
213 cpf_revoke(cp_grant_id_t g)
215 /* Revoke previously granted access, identified by grant id. */
216 GID_CHECK_USED(g);
218 /* Make grant invalid by setting flags to 0, clearing CPF_USED.
219 * This invalidates the grant.
221 grants[g].cp_flags = 0;
223 return 0;
227 cpf_lookup(cp_grant_id_t g, endpoint_t *granter, endpoint_t *grantee)
229 /* First check slot validity, and if it's in use currently. */
230 GID_CHECK_USED(g);
232 if(grants[g].cp_flags & CPF_DIRECT) {
233 if(granter) *granter = SELF;
234 if(grantee) *grantee = grants[g].cp_u.cp_direct.cp_who_to;
235 } else if(grants[g].cp_flags & CPF_MAGIC) {
236 if(granter) *granter = grants[g].cp_u.cp_magic.cp_who_from;
237 if(grantee) *grantee = grants[g].cp_u.cp_magic.cp_who_to;
238 } else return -1;
240 return 0;
244 cpf_getgrants(cp_grant_id_t *grant_ids, int n)
246 int i;
248 for(i = 0; i < n; i++) {
249 if((grant_ids[i] = cpf_new_grantslot()) < 0)
250 break;
251 grants[grant_ids[i]].cp_flags = CPF_USED;
254 /* return however many grants were assigned. */
255 return i;
259 cpf_setgrant_direct(gid, who, addr, bytes, access)
260 cp_grant_id_t gid;
261 endpoint_t who;
262 vir_bytes addr;
263 size_t bytes;
264 int access;
266 GID_CHECK(gid);
267 ACCESS_CHECK(access);
269 /* Fill in new slot data. */
270 grants[gid].cp_flags = access | CPF_DIRECT | CPF_USED | CPF_VALID;
271 grants[gid].cp_u.cp_direct.cp_who_to = who;
272 grants[gid].cp_u.cp_direct.cp_start = addr;
273 grants[gid].cp_u.cp_direct.cp_len = bytes;
275 return 0;
279 cpf_setgrant_indirect(gid, who_to, who_from, his_gid)
280 cp_grant_id_t gid;
281 endpoint_t who_to, who_from;
282 cp_grant_id_t his_gid;
284 GID_CHECK(gid);
286 /* Fill in new slot data. */
287 grants[gid].cp_flags = CPF_USED | CPF_INDIRECT | CPF_VALID;
288 grants[gid].cp_u.cp_indirect.cp_who_to = who_to;
289 grants[gid].cp_u.cp_indirect.cp_who_from = who_from;
290 grants[gid].cp_u.cp_indirect.cp_grant = his_gid;
292 return 0;
296 cpf_setgrant_magic(gid, who_to, who_from, addr, bytes, access)
297 cp_grant_id_t gid;
298 endpoint_t who_to, who_from;
299 vir_bytes addr;
300 size_t bytes;
301 int access;
303 GID_CHECK(gid);
304 ACCESS_CHECK(access);
306 /* Fill in new slot data. */
307 grants[gid].cp_flags = CPF_USED | CPF_MAGIC | CPF_VALID | access;
308 grants[gid].cp_u.cp_magic.cp_who_to = who_to;
309 grants[gid].cp_u.cp_magic.cp_who_from = who_from;
310 grants[gid].cp_u.cp_magic.cp_start = addr;
311 grants[gid].cp_u.cp_magic.cp_len = bytes;
313 return 0;
317 cpf_setgrant_disable(gid)
318 cp_grant_id_t gid;
320 GID_CHECK(gid);
322 /* Grant is now no longer valid, but still in use. */
323 grants[gid].cp_flags = CPF_USED;
325 return 0;
328 void
329 cpf_reload(void)
331 /* Inform the kernel about the location of the grant table. This is needed
332 * after a fork.
334 if (grants)
335 sys_setgrant(grants, ngrants); /* Do we need error checking? */