1 /* $NetBSD: puffs_compat.c,v 1.4 2015/04/22 17:07:24 pooka 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.4 2015/04/22 17:07:24 pooka 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 48 #include <dev/putter/putter_sys.h> 49 50 #include <fs/puffs/puffs_msgif.h> 51 #include <fs/puffs/puffs_sys.h> 52 53 #include <compat/sys/time.h> 54 55 /* 56 * compat types 57 */ 58 struct vattr50 { 59 enum vtype va_type; 60 mode_t va_mode; 61 nlink_t va_nlink; 62 uid_t va_uid; 63 gid_t va_gid; 64 uint32_t va_fsid; 65 ino_t va_fileid; 66 u_quad_t va_size; 67 long va_blocksize; 68 struct timespec50 va_atime; 69 struct timespec50 va_mtime; 70 struct timespec50 va_ctime; 71 struct timespec50 va_birthtime; 72 u_long va_gen; 73 u_long va_flags; 74 uint32_t va_rdev; 75 u_quad_t va_bytes; 76 u_quad_t va_filerev; 77 u_int va_vaflags; 78 long va_spare; 79 }; 80 81 struct puffs50_vfsmsg_fhtonode { 82 struct puffs_req pvfsr_pr; 83 84 void *pvfsr_fhcookie; /* IN */ 85 enum vtype pvfsr_vtype; /* IN */ 86 voff_t pvfsr_size; /* IN */ 87 uint32_t pvfsr_rdev; /* IN */ 88 89 size_t pvfsr_dsize; /* OUT */ 90 uint8_t pvfsr_data[0] /* OUT, XXX */ 91 __aligned(ALIGNBYTES+1); 92 }; 93 94 struct puffs50_vnmsg_lookup { 95 struct puffs_req pvn_pr; 96 97 struct puffs_kcn pvnr_cn; /* OUT */ 98 struct puffs_kcred pvnr_cn_cred; /* OUT */ 99 100 puffs_cookie_t pvnr_newnode; /* IN */ 101 enum vtype pvnr_vtype; /* IN */ 102 voff_t pvnr_size; /* IN */ 103 uint32_t pvnr_rdev; /* IN */ 104 }; 105 106 struct puffs50_vnmsg_create { 107 struct puffs_req pvn_pr; 108 109 struct puffs_kcn pvnr_cn; /* OUT */ 110 struct puffs_kcred pvnr_cn_cred; /* OUT */ 111 112 struct vattr50 pvnr_va; /* OUT */ 113 puffs_cookie_t pvnr_newnode; /* IN */ 114 }; 115 116 struct puffs50_vnmsg_mknod { 117 struct puffs_req pvn_pr; 118 119 struct puffs_kcn pvnr_cn; /* OUT */ 120 struct puffs_kcred pvnr_cn_cred; /* OUT */ 121 122 struct vattr50 pvnr_va; /* OUT */ 123 puffs_cookie_t pvnr_newnode; /* IN */ 124 }; 125 126 #define puffs50_vnmsg_setattr puffs50_vnmsg_setgetattr 127 #define puffs50_vnmsg_getattr puffs50_vnmsg_setgetattr 128 struct puffs50_vnmsg_setgetattr { 129 struct puffs_req pvn_pr; 130 131 struct puffs_kcred pvnr_cred; /* OUT */ 132 struct vattr50 pvnr_va; /* IN/OUT (op depend) */ 133 }; 134 135 struct puffs50_vnmsg_mkdir { 136 struct puffs_req pvn_pr; 137 138 struct puffs_kcn pvnr_cn; /* OUT */ 139 struct puffs_kcred pvnr_cn_cred; /* OUT */ 140 141 struct vattr50 pvnr_va; /* OUT */ 142 puffs_cookie_t pvnr_newnode; /* IN */ 143 }; 144 145 struct puffs50_vnmsg_symlink { 146 struct puffs_req pvn_pr; 147 148 struct puffs_kcn pvnr_cn; /* OUT */ 149 struct puffs_kcred pvnr_cn_cred; /* OUT */ 150 151 struct vattr50 pvnr_va; /* OUT */ 152 puffs_cookie_t pvnr_newnode; /* IN */ 153 char pvnr_link[MAXPATHLEN]; /* OUT */ 154 }; 155 156 /* 157 * vattr translation routines 158 */ 159 160 #ifdef COMPAT_50 161 static void 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 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 #endif /* COMPAT_50 */ 211 212 /* 213 * XXX: cannot assert that sleeping is possible 214 * (this always a valid assumption for now) 215 */ 216 #define INIT(name, extra) \ 217 struct puffs50_##name *cmsg; \ 218 struct puffs_##name *omsg; \ 219 creq =kmem_zalloc(sizeof(struct puffs50_##name)+extra,KM_SLEEP);\ 220 cmsg = (struct puffs50_##name *)creq; \ 221 omsg = (struct puffs_##name *)oreq; \ 222 delta = sizeof(struct puffs50_##name)-sizeof(struct puffs_##name); 223 #define ASSIGN(field) \ 224 cmsg->field = omsg->field; 225 226 bool 227 puffs_compat_outgoing(struct puffs_req *oreq, 228 struct puffs_req **creqp, ssize_t *deltap) 229 { 230 bool rv = false; 231 #ifdef COMPAT_50 232 struct puffs_req *creq = NULL; 233 ssize_t delta = 0; 234 235 if (PUFFSOP_OPCLASS(oreq->preq_opclass) == PUFFSOP_VFS 236 && oreq->preq_optype == PUFFS_VFS_FHTOVP) { 237 INIT(vfsmsg_fhtonode, 238 ((struct puffs_vfsmsg_fhtonode *)oreq)->pvfsr_dsize); 239 240 ASSIGN(pvfsr_pr); 241 ASSIGN(pvfsr_dsize); 242 memcpy(cmsg->pvfsr_data, omsg->pvfsr_data, cmsg->pvfsr_dsize); 243 } else if (PUFFSOP_OPCLASS(oreq->preq_opclass) == PUFFSOP_VN) { 244 switch (oreq->preq_optype) { 245 case PUFFS_VN_LOOKUP: 246 { 247 INIT(vnmsg_lookup, 0); 248 249 ASSIGN(pvn_pr); 250 ASSIGN(pvnr_cn); 251 ASSIGN(pvnr_cn_cred); 252 253 break; 254 } 255 256 case PUFFS_VN_CREATE: 257 { 258 INIT(vnmsg_create, 0); 259 260 ASSIGN(pvn_pr); 261 ASSIGN(pvnr_cn); 262 ASSIGN(pvnr_cn_cred); 263 vattr_to_50(&omsg->pvnr_va, &cmsg->pvnr_va); 264 265 break; 266 } 267 268 case PUFFS_VN_MKNOD: 269 { 270 INIT(vnmsg_mknod, 0); 271 272 ASSIGN(pvn_pr); 273 ASSIGN(pvnr_cn); 274 ASSIGN(pvnr_cn_cred); 275 vattr_to_50(&omsg->pvnr_va, &cmsg->pvnr_va); 276 277 break; 278 } 279 280 case PUFFS_VN_MKDIR: 281 { 282 INIT(vnmsg_mkdir, 0); 283 284 ASSIGN(pvn_pr); 285 ASSIGN(pvnr_cn); 286 ASSIGN(pvnr_cn_cred); 287 vattr_to_50(&omsg->pvnr_va, &cmsg->pvnr_va); 288 289 break; 290 } 291 292 case PUFFS_VN_SYMLINK: 293 { 294 INIT(vnmsg_symlink, 0); 295 296 ASSIGN(pvn_pr); 297 ASSIGN(pvnr_cn); 298 ASSIGN(pvnr_cn_cred); 299 vattr_to_50(&omsg->pvnr_va, &cmsg->pvnr_va); 300 memcpy(cmsg->pvnr_link, omsg->pvnr_link, 301 sizeof(cmsg->pvnr_link)); 302 303 break; 304 } 305 306 case PUFFS_VN_SETATTR: 307 { 308 INIT(vnmsg_setattr, 0); 309 310 ASSIGN(pvn_pr); 311 ASSIGN(pvnr_cred); 312 vattr_to_50(&omsg->pvnr_va, &cmsg->pvnr_va); 313 314 break; 315 } 316 case PUFFS_VN_GETATTR: 317 { 318 INIT(vnmsg_getattr, 0); 319 320 ASSIGN(pvn_pr); 321 ASSIGN(pvnr_cred); 322 323 break; 324 } 325 326 default: 327 break; 328 } 329 } 330 331 if (creq) { 332 *creqp = creq; 333 *deltap = delta; 334 rv = true; 335 } 336 #endif 337 338 return rv; 339 } 340 #undef INIT 341 #undef ASSIGN 342 343 #define INIT(name) \ 344 struct puffs50_##name *cmsg = (void *)preq; \ 345 struct puffs_##name *omsg = (void *)creq; 346 #define ASSIGN(field) \ 347 omsg->field = cmsg->field; 348 349 void 350 puffs_compat_incoming(struct puffs_req *preq, struct puffs_req *creq) 351 { 352 353 #ifdef COMPAT_50 354 if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VFS 355 && preq->preq_optype == PUFFS_VFS_FHTOVP) { 356 INIT(vfsmsg_fhtonode); 357 358 ASSIGN(pvfsr_pr); 359 360 ASSIGN(pvfsr_fhcookie); 361 ASSIGN(pvfsr_vtype); 362 ASSIGN(pvfsr_size); 363 ASSIGN(pvfsr_rdev); 364 } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN) { 365 switch (preq->preq_optype) { 366 case PUFFS_VN_LOOKUP: 367 { 368 INIT(vnmsg_lookup); 369 370 ASSIGN(pvn_pr); 371 ASSIGN(pvnr_newnode); 372 ASSIGN(pvnr_vtype); 373 ASSIGN(pvnr_size); 374 ASSIGN(pvnr_rdev); 375 376 break; 377 } 378 379 case PUFFS_VN_CREATE: 380 { 381 INIT(vnmsg_create); 382 383 ASSIGN(pvn_pr); 384 ASSIGN(pvnr_newnode); 385 386 break; 387 } 388 389 case PUFFS_VN_MKNOD: 390 { 391 INIT(vnmsg_mknod); 392 393 ASSIGN(pvn_pr); 394 ASSIGN(pvnr_newnode); 395 396 break; 397 } 398 399 case PUFFS_VN_MKDIR: 400 { 401 INIT(vnmsg_mkdir); 402 403 ASSIGN(pvn_pr); 404 ASSIGN(pvnr_newnode); 405 406 break; 407 } 408 409 case PUFFS_VN_SYMLINK: 410 { 411 INIT(vnmsg_symlink); 412 413 ASSIGN(pvn_pr); 414 ASSIGN(pvnr_newnode); 415 416 break; 417 } 418 419 case PUFFS_VN_SETATTR: 420 { 421 INIT(vnmsg_setattr); 422 423 ASSIGN(pvn_pr); 424 425 break; 426 } 427 case PUFFS_VN_GETATTR: 428 { 429 INIT(vnmsg_getattr); 430 431 ASSIGN(pvn_pr); 432 vattr_from_50(&cmsg->pvnr_va, &omsg->pvnr_va); 433 434 break; 435 } 436 437 default: 438 panic("puffs compat ops come in pairs"); 439 } 440 } 441 #endif /* COMPAT_50 */ 442 } 443