Home | History | Annotate | Line # | Download | only in puffs
      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
    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 
    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
    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
    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 
    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 
    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