1 /* $NetBSD: puffs_compat.c,v 1.8 2019/12/12 02:15:43 pgoyette Exp $ */
2
3 /*
4 * Copyright (c) 2010 Antti Kantee. All Rights Reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 /*
29 * This file handles puffs PDUs so that they are compatible between
30 * 32bit<->64bit time_t/dev_t. It enables running a -current kernel
31 * against a 5.0 userland (assuming the protocol otherwise matches!).
32 */
33
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: puffs_compat.c,v 1.8 2019/12/12 02:15:43 pgoyette Exp $");
36
37 #include <sys/param.h>
38 #include <sys/atomic.h>
39 #include <sys/kmem.h>
40 #include <sys/kthread.h>
41 #include <sys/lock.h>
42 #include <sys/mount.h>
43 #include <sys/namei.h>
44 #include <sys/proc.h>
45 #include <sys/vnode.h>
46 #include <sys/atomic.h>
47 #include <sys/compat_stub.h>
48
49 #include <dev/putter/putter_sys.h>
50
51 #include <fs/puffs/puffs_msgif.h>
52 #include <fs/puffs/puffs_sys.h>
53
54 #include <compat/sys/time.h>
55
56 /*
57 * compat types
58 */
59 struct vattr50 {
60 enum vtype va_type;
61 mode_t va_mode;
62 nlink_t va_nlink;
63 uid_t va_uid;
64 gid_t va_gid;
65 uint32_t va_fsid;
66 ino_t va_fileid;
67 u_quad_t va_size;
68 long va_blocksize;
69 struct timespec50 va_atime;
70 struct timespec50 va_mtime;
71 struct timespec50 va_ctime;
72 struct timespec50 va_birthtime;
73 u_long va_gen;
74 u_long va_flags;
75 uint32_t va_rdev;
76 u_quad_t va_bytes;
77 u_quad_t va_filerev;
78 u_int va_vaflags;
79 long va_spare;
80 };
81
82 struct puffs50_vfsmsg_fhtonode {
83 struct puffs_req pvfsr_pr;
84
85 void *pvfsr_fhcookie; /* IN */
86 enum vtype pvfsr_vtype; /* IN */
87 voff_t pvfsr_size; /* IN */
88 uint32_t pvfsr_rdev; /* IN */
89
90 size_t pvfsr_dsize; /* OUT */
91 uint8_t pvfsr_data[0] /* OUT, XXX */
92 __aligned(ALIGNBYTES+1);
93 };
94
95 struct puffs50_vnmsg_lookup {
96 struct puffs_req pvn_pr;
97
98 struct puffs_kcn pvnr_cn; /* OUT */
99 struct puffs_kcred pvnr_cn_cred; /* OUT */
100
101 puffs_cookie_t pvnr_newnode; /* IN */
102 enum vtype pvnr_vtype; /* IN */
103 voff_t pvnr_size; /* IN */
104 uint32_t pvnr_rdev; /* IN */
105 };
106
107 struct puffs50_vnmsg_create {
108 struct puffs_req pvn_pr;
109
110 struct puffs_kcn pvnr_cn; /* OUT */
111 struct puffs_kcred pvnr_cn_cred; /* OUT */
112
113 struct vattr50 pvnr_va; /* OUT */
114 puffs_cookie_t pvnr_newnode; /* IN */
115 };
116
117 struct puffs50_vnmsg_mknod {
118 struct puffs_req pvn_pr;
119
120 struct puffs_kcn pvnr_cn; /* OUT */
121 struct puffs_kcred pvnr_cn_cred; /* OUT */
122
123 struct vattr50 pvnr_va; /* OUT */
124 puffs_cookie_t pvnr_newnode; /* IN */
125 };
126
127 #define puffs50_vnmsg_setattr puffs50_vnmsg_setgetattr
128 #define puffs50_vnmsg_getattr puffs50_vnmsg_setgetattr
129 struct puffs50_vnmsg_setgetattr {
130 struct puffs_req pvn_pr;
131
132 struct puffs_kcred pvnr_cred; /* OUT */
133 struct vattr50 pvnr_va; /* IN/OUT (op depend) */
134 };
135
136 struct puffs50_vnmsg_mkdir {
137 struct puffs_req pvn_pr;
138
139 struct puffs_kcn pvnr_cn; /* OUT */
140 struct puffs_kcred pvnr_cn_cred; /* OUT */
141
142 struct vattr50 pvnr_va; /* OUT */
143 puffs_cookie_t pvnr_newnode; /* IN */
144 };
145
146 struct puffs50_vnmsg_symlink {
147 struct puffs_req pvn_pr;
148
149 struct puffs_kcn pvnr_cn; /* OUT */
150 struct puffs_kcred pvnr_cn_cred; /* OUT */
151
152 struct vattr50 pvnr_va; /* OUT */
153 puffs_cookie_t pvnr_newnode; /* IN */
154 char pvnr_link[MAXPATHLEN]; /* OUT */
155 };
156
157 /*
158 * vattr translation routines
159 */
160
161 static void
vattr_to_50(const struct vattr * va,struct vattr50 * va50)162 vattr_to_50(const struct vattr *va, struct vattr50 *va50)
163 {
164
165 va50->va_type = va->va_type;
166 va50->va_mode = va->va_mode;
167 va50->va_nlink = va->va_nlink;
168 va50->va_uid = va->va_uid;
169 va50->va_gid = va->va_gid;
170 va50->va_fsid = (uint64_t)va->va_fsid;
171 va50->va_fileid = va->va_fileid;
172 va50->va_size = va->va_size;
173 va50->va_blocksize = va->va_blocksize;
174 timespec_to_timespec50(&va->va_atime, &va50->va_atime);
175 timespec_to_timespec50(&va->va_ctime, &va50->va_ctime);
176 timespec_to_timespec50(&va->va_mtime, &va50->va_mtime);
177 timespec_to_timespec50(&va->va_birthtime, &va50->va_birthtime);
178 va50->va_gen = va->va_gen;
179 va50->va_flags = va->va_flags;
180 va50->va_rdev = (int32_t)va->va_rdev;
181 va50->va_bytes = va->va_bytes;
182 va50->va_filerev = va->va_filerev;
183 va50->va_vaflags = va->va_flags;
184 }
185
186 static void
vattr_from_50(const struct vattr50 * va50,struct vattr * va)187 vattr_from_50(const struct vattr50 *va50, struct vattr *va)
188 {
189
190 va->va_type = va50->va_type;
191 va->va_mode = va50->va_mode;
192 va->va_nlink = va50->va_nlink;
193 va->va_uid = va50->va_uid;
194 va->va_gid = va50->va_gid;
195 va->va_fsid = (uint32_t)va50->va_fsid;
196 va->va_fileid = va50->va_fileid;
197 va->va_size = va50->va_size;
198 va->va_blocksize = va50->va_blocksize;
199 timespec50_to_timespec(&va50->va_atime, &va->va_atime);
200 timespec50_to_timespec(&va50->va_ctime, &va->va_ctime);
201 timespec50_to_timespec(&va50->va_mtime, &va->va_mtime);
202 timespec50_to_timespec(&va50->va_birthtime, &va->va_birthtime);
203 va->va_gen = va50->va_gen;
204 va->va_flags = va50->va_flags;
205 va->va_rdev = (uint32_t)va50->va_rdev;
206 va->va_bytes = va50->va_bytes;
207 va->va_filerev = va50->va_filerev;
208 va->va_vaflags = va50->va_flags;
209 }
210
211 /*
212 * XXX: cannot assert that sleeping is possible
213 * (this always a valid assumption for now)
214 */
215 #define INIT(name, extra) \
216 struct puffs50_##name *cmsg; \
217 struct puffs_##name *omsg; \
218 creq =kmem_zalloc(sizeof(struct puffs50_##name)+extra,KM_SLEEP);\
219 cmsg = (struct puffs50_##name *)creq; \
220 omsg = (struct puffs_##name *)oreq; \
221 delta = sizeof(struct puffs50_##name)-sizeof(struct puffs_##name);
222 #define ASSIGN(field) \
223 cmsg->field = omsg->field;
224
225 int
puffs_compat_outgoing(struct puffs_req * oreq,struct puffs_req ** creqp,ssize_t * deltap)226 puffs_compat_outgoing(struct puffs_req *oreq,
227 struct puffs_req **creqp, ssize_t *deltap)
228 {
229 int rv = ENOSYS; /* non-zero return ==> false */
230 struct puffs_req *creq = NULL;
231 ssize_t delta = 0;
232
233 if (PUFFSOP_OPCLASS(oreq->preq_opclass) == PUFFSOP_VFS
234 && oreq->preq_optype == PUFFS_VFS_FHTOVP) {
235 INIT(vfsmsg_fhtonode,
236 ((struct puffs_vfsmsg_fhtonode *)oreq)->pvfsr_dsize);
237
238 ASSIGN(pvfsr_pr);
239 ASSIGN(pvfsr_dsize);
240 memcpy(cmsg->pvfsr_data, omsg->pvfsr_data, cmsg->pvfsr_dsize);
241 } else if (PUFFSOP_OPCLASS(oreq->preq_opclass) == PUFFSOP_VN) {
242 switch (oreq->preq_optype) {
243 case PUFFS_VN_LOOKUP:
244 {
245 INIT(vnmsg_lookup, 0);
246
247 ASSIGN(pvn_pr);
248 ASSIGN(pvnr_cn);
249 ASSIGN(pvnr_cn_cred);
250
251 break;
252 }
253
254 case PUFFS_VN_CREATE:
255 {
256 INIT(vnmsg_create, 0);
257
258 ASSIGN(pvn_pr);
259 ASSIGN(pvnr_cn);
260 ASSIGN(pvnr_cn_cred);
261 vattr_to_50(&omsg->pvnr_va, &cmsg->pvnr_va);
262
263 break;
264 }
265
266 case PUFFS_VN_MKNOD:
267 {
268 INIT(vnmsg_mknod, 0);
269
270 ASSIGN(pvn_pr);
271 ASSIGN(pvnr_cn);
272 ASSIGN(pvnr_cn_cred);
273 vattr_to_50(&omsg->pvnr_va, &cmsg->pvnr_va);
274
275 break;
276 }
277
278 case PUFFS_VN_MKDIR:
279 {
280 INIT(vnmsg_mkdir, 0);
281
282 ASSIGN(pvn_pr);
283 ASSIGN(pvnr_cn);
284 ASSIGN(pvnr_cn_cred);
285 vattr_to_50(&omsg->pvnr_va, &cmsg->pvnr_va);
286
287 break;
288 }
289
290 case PUFFS_VN_SYMLINK:
291 {
292 INIT(vnmsg_symlink, 0);
293
294 ASSIGN(pvn_pr);
295 ASSIGN(pvnr_cn);
296 ASSIGN(pvnr_cn_cred);
297 vattr_to_50(&omsg->pvnr_va, &cmsg->pvnr_va);
298 memcpy(cmsg->pvnr_link, omsg->pvnr_link,
299 sizeof(cmsg->pvnr_link));
300
301 break;
302 }
303
304 case PUFFS_VN_SETATTR:
305 {
306 INIT(vnmsg_setattr, 0);
307
308 ASSIGN(pvn_pr);
309 ASSIGN(pvnr_cred);
310 vattr_to_50(&omsg->pvnr_va, &cmsg->pvnr_va);
311
312 break;
313 }
314 case PUFFS_VN_GETATTR:
315 {
316 INIT(vnmsg_getattr, 0);
317
318 ASSIGN(pvn_pr);
319 ASSIGN(pvnr_cred);
320
321 break;
322 }
323
324 default:
325 break;
326 }
327 }
328
329 if (creq) {
330 *creqp = creq;
331 *deltap = delta;
332 rv = 0;
333 }
334
335 return rv;
336 }
337 #undef INIT
338 #undef ASSIGN
339
340 #define INIT(name) \
341 struct puffs50_##name *cmsg = (void *)preq; \
342 struct puffs_##name *omsg = (void *)creq;
343 #define ASSIGN(field) \
344 omsg->field = cmsg->field;
345
346 void
puffs_compat_incoming(struct puffs_req * preq,struct puffs_req * creq)347 puffs_compat_incoming(struct puffs_req *preq, struct puffs_req *creq)
348 {
349
350 if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VFS
351 && preq->preq_optype == PUFFS_VFS_FHTOVP) {
352 INIT(vfsmsg_fhtonode);
353
354 ASSIGN(pvfsr_pr);
355
356 ASSIGN(pvfsr_fhcookie);
357 ASSIGN(pvfsr_vtype);
358 ASSIGN(pvfsr_size);
359 ASSIGN(pvfsr_rdev);
360 } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN) {
361 switch (preq->preq_optype) {
362 case PUFFS_VN_LOOKUP:
363 {
364 INIT(vnmsg_lookup);
365
366 ASSIGN(pvn_pr);
367 ASSIGN(pvnr_newnode);
368 ASSIGN(pvnr_vtype);
369 ASSIGN(pvnr_size);
370 ASSIGN(pvnr_rdev);
371
372 break;
373 }
374
375 case PUFFS_VN_CREATE:
376 {
377 INIT(vnmsg_create);
378
379 ASSIGN(pvn_pr);
380 ASSIGN(pvnr_newnode);
381
382 break;
383 }
384
385 case PUFFS_VN_MKNOD:
386 {
387 INIT(vnmsg_mknod);
388
389 ASSIGN(pvn_pr);
390 ASSIGN(pvnr_newnode);
391
392 break;
393 }
394
395 case PUFFS_VN_MKDIR:
396 {
397 INIT(vnmsg_mkdir);
398
399 ASSIGN(pvn_pr);
400 ASSIGN(pvnr_newnode);
401
402 break;
403 }
404
405 case PUFFS_VN_SYMLINK:
406 {
407 INIT(vnmsg_symlink);
408
409 ASSIGN(pvn_pr);
410 ASSIGN(pvnr_newnode);
411
412 break;
413 }
414
415 case PUFFS_VN_SETATTR:
416 {
417 INIT(vnmsg_setattr);
418
419 ASSIGN(pvn_pr);
420
421 break;
422 }
423 case PUFFS_VN_GETATTR:
424 {
425 INIT(vnmsg_getattr);
426
427 ASSIGN(pvn_pr);
428 vattr_from_50(&cmsg->pvnr_va, &omsg->pvnr_va);
429
430 break;
431 }
432
433 default:
434 panic("puffs compat ops come in pairs");
435 }
436 }
437 }
438
puffs_50_init(void)439 void puffs_50_init(void)
440 {
441
442 MODULE_HOOK_SET(puffs_out_50_hook, puffs_compat_outgoing);
443 MODULE_HOOK_SET(puffs_in_50_hook, puffs_compat_incoming);
444 }
445
puffs_50_fini(void)446 void puffs_50_fini(void)
447 {
448
449 MODULE_HOOK_UNSET(puffs_out_50_hook);
450 MODULE_HOOK_UNSET(puffs_in_50_hook);
451 }
452