From b90c150c5e8487bbe1f71d70e0134349b1455401 Mon Sep 17 00:00:00 2001 From: pooka Date: Tue, 6 Jul 2010 13:47:47 +0000 Subject: [PATCH] Add compat to enable running puffs in a 64bit time_t kernel against a server which runs in 32bit time_t namespace. --- sys/fs/puffs/puffs_compat.c | 434 ++++++++++++++++++++++++++++++++++++ sys/fs/puffs/puffs_msgif.c | 54 ++++- sys/fs/puffs/puffs_msgif.h | 6 +- sys/fs/puffs/puffs_sys.h | 6 +- sys/fs/puffs/puffs_vfsops.c | 5 +- 5 files changed, 493 insertions(+), 12 deletions(-) create mode 100644 sys/fs/puffs/puffs_compat.c diff --git a/sys/fs/puffs/puffs_compat.c b/sys/fs/puffs/puffs_compat.c new file mode 100644 index 000000000000..72d3775e48e1 --- /dev/null +++ b/sys/fs/puffs/puffs_compat.c @@ -0,0 +1,434 @@ +/* $NetBSD: puffs_compat.c,v 1.1 2010/07/06 13:47:47 pooka Exp $ */ + +/* + * Copyright (c) 2010 Antti Kantee. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This file handles puffs PDUs so that they are compatible between + * 32bit<->64bit time_t/dev_t. It enables running a -current kernel + * against a 5.0 userland (assuming the protocol otherwise matches!). + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: puffs_compat.c,v 1.1 2010/07/06 13:47:47 pooka Exp $"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +/* + * compat types + */ +struct vattr50 { + enum vtype va_type; + mode_t va_mode; + nlink_t va_nlink; + uid_t va_uid; + gid_t va_gid; + uint32_t va_fsid; + ino_t va_fileid; + u_quad_t va_size; + long va_blocksize; + struct timespec50 va_atime; + struct timespec50 va_mtime; + struct timespec50 va_ctime; + struct timespec50 va_birthtime; + u_long va_gen; + u_long va_flags; + uint32_t va_rdev; + u_quad_t va_bytes; + u_quad_t va_filerev; + u_int va_vaflags; + long va_spare; +}; + +struct puffs50_vfsmsg_fhtonode { + struct puffs_req pvfsr_pr; + + void *pvfsr_fhcookie; /* IN */ + enum vtype pvfsr_vtype; /* IN */ + voff_t pvfsr_size; /* IN */ + uint32_t pvfsr_rdev; /* IN */ + + size_t pvfsr_dsize; /* OUT */ + uint8_t pvfsr_data[0] /* OUT, XXX */ + __aligned(ALIGNBYTES+1); +}; + +struct puffs50_vnmsg_lookup { + struct puffs_req pvn_pr; + + struct puffs_kcn pvnr_cn; /* OUT */ + struct puffs_kcred pvnr_cn_cred; /* OUT */ + + puffs_cookie_t pvnr_newnode; /* IN */ + enum vtype pvnr_vtype; /* IN */ + voff_t pvnr_size; /* IN */ + uint32_t pvnr_rdev; /* IN */ +}; + +struct puffs50_vnmsg_create { + struct puffs_req pvn_pr; + + struct puffs_kcn pvnr_cn; /* OUT */ + struct puffs_kcred pvnr_cn_cred; /* OUT */ + + struct vattr50 pvnr_va; /* OUT */ + puffs_cookie_t pvnr_newnode; /* IN */ +}; + +struct puffs50_vnmsg_mknod { + struct puffs_req pvn_pr; + + struct puffs_kcn pvnr_cn; /* OUT */ + struct puffs_kcred pvnr_cn_cred; /* OUT */ + + struct vattr50 pvnr_va; /* OUT */ + puffs_cookie_t pvnr_newnode; /* IN */ +}; + +#define puffs50_vnmsg_setattr puffs50_vnmsg_setgetattr +#define puffs50_vnmsg_getattr puffs50_vnmsg_setgetattr +struct puffs50_vnmsg_setgetattr { + struct puffs_req pvn_pr; + + struct puffs_kcred pvnr_cred; /* OUT */ + struct vattr50 pvnr_va; /* IN/OUT (op depend) */ +}; + +struct puffs50_vnmsg_mkdir { + struct puffs_req pvn_pr; + + struct puffs_kcn pvnr_cn; /* OUT */ + struct puffs_kcred pvnr_cn_cred; /* OUT */ + + struct vattr50 pvnr_va; /* OUT */ + puffs_cookie_t pvnr_newnode; /* IN */ +}; + +struct puffs50_vnmsg_symlink { + struct puffs_req pvn_pr; + + struct puffs_kcn pvnr_cn; /* OUT */ + struct puffs_kcred pvnr_cn_cred; /* OUT */ + + struct vattr50 pvnr_va; /* OUT */ + puffs_cookie_t pvnr_newnode; /* IN */ + char pvnr_link[MAXPATHLEN]; /* OUT */ +}; + +/* + * vattr translation routines + */ + +static void +vattr_to_50(const struct vattr *va, struct vattr50 *va50) +{ + + va50->va_type = va->va_type; + va50->va_mode = va->va_mode; + va50->va_nlink = va->va_nlink; + va50->va_uid = va->va_uid; + va50->va_gid = va->va_gid; + va50->va_fsid = (uint64_t)va->va_fsid; + va50->va_fileid = va->va_fileid; + va50->va_size = va->va_size; + va50->va_blocksize = va->va_blocksize; + timespec_to_timespec50(&va->va_atime, &va50->va_atime); + timespec_to_timespec50(&va->va_ctime, &va50->va_ctime); + timespec_to_timespec50(&va->va_mtime, &va50->va_mtime); + timespec_to_timespec50(&va->va_birthtime, &va50->va_birthtime); + va50->va_gen = va->va_gen; + va50->va_flags = va->va_flags; + va50->va_rdev = (int32_t)va->va_rdev; + va50->va_bytes = va->va_bytes; + va50->va_filerev = va->va_filerev; + va50->va_vaflags = va->va_flags; +} + +static void +vattr_from_50(const struct vattr50 *va50, struct vattr *va) +{ + + va->va_type = va50->va_type; + va->va_mode = va50->va_mode; + va->va_nlink = va50->va_nlink; + va->va_uid = va50->va_uid; + va->va_gid = va50->va_gid; + va->va_fsid = (uint32_t)va50->va_fsid; + va->va_fileid = va50->va_fileid; + va->va_size = va50->va_size; + va->va_blocksize = va50->va_blocksize; + timespec50_to_timespec(&va50->va_atime, &va->va_atime); + timespec50_to_timespec(&va50->va_ctime, &va->va_ctime); + timespec50_to_timespec(&va50->va_mtime, &va->va_mtime); + timespec50_to_timespec(&va50->va_birthtime, &va->va_birthtime); + va->va_gen = va50->va_gen; + va->va_flags = va50->va_flags; + va->va_rdev = (uint32_t)va50->va_rdev; + va->va_bytes = va50->va_bytes; + va->va_filerev = va50->va_filerev; + va->va_vaflags = va50->va_flags; +} + +/* + * XXX: cannot assert that sleeping is possible + * (this always a valid assumption for now) + */ +#define INIT(name) \ + struct puffs50_##name *cmsg; \ + struct puffs_##name *omsg; \ + creq = kmem_zalloc(sizeof(struct puffs50_##name), KM_SLEEP); \ + cmsg = (struct puffs50_##name *)creq; \ + omsg = (struct puffs_##name *)oreq; \ + delta = sizeof(struct puffs50_##name)-sizeof(struct puffs_##name); +#define ASSIGN(field) \ + cmsg->field = omsg->field; + +bool +puffs_compat_outgoing(struct puffs_req *oreq, + struct puffs_req **creqp, ssize_t *deltap) +{ + struct puffs_req *creq = NULL; + ssize_t delta = 0; + bool rv = false; + + if (PUFFSOP_OPCLASS(oreq->preq_opclass == PUFFSOP_VFS)) { + INIT(vfsmsg_fhtonode); + + ASSIGN(pvfsr_pr); + ASSIGN(pvfsr_dsize); + memcpy(cmsg->pvfsr_data, omsg->pvfsr_data, cmsg->pvfsr_dsize); + } else if (PUFFSOP_OPCLASS(oreq->preq_opclass) == PUFFSOP_VN) { + switch (oreq->preq_optype) { + case PUFFS_VN_LOOKUP: + { + INIT(vnmsg_lookup); + + ASSIGN(pvn_pr); + ASSIGN(pvnr_cn); + ASSIGN(pvnr_cn_cred); + + break; + } + + case PUFFS_VN_CREATE: + { + INIT(vnmsg_create); + + ASSIGN(pvn_pr); + ASSIGN(pvnr_cn); + ASSIGN(pvnr_cn_cred); + vattr_to_50(&omsg->pvnr_va, &cmsg->pvnr_va); + + break; + } + + case PUFFS_VN_MKNOD: + { + INIT(vnmsg_mknod); + + ASSIGN(pvn_pr); + ASSIGN(pvnr_cn); + ASSIGN(pvnr_cn_cred); + vattr_to_50(&omsg->pvnr_va, &cmsg->pvnr_va); + + break; + } + + case PUFFS_VN_MKDIR: + { + INIT(vnmsg_mkdir); + + ASSIGN(pvn_pr); + ASSIGN(pvnr_cn); + ASSIGN(pvnr_cn_cred); + vattr_to_50(&omsg->pvnr_va, &cmsg->pvnr_va); + + break; + } + + case PUFFS_VN_SYMLINK: + { + INIT(vnmsg_symlink); + + ASSIGN(pvn_pr); + ASSIGN(pvnr_cn); + ASSIGN(pvnr_cn_cred); + vattr_to_50(&omsg->pvnr_va, &cmsg->pvnr_va); + memcpy(cmsg->pvnr_link, omsg->pvnr_link, + sizeof(cmsg->pvnr_link)); + + break; + } + + case PUFFS_VN_SETATTR: + { + INIT(vnmsg_setattr); + + ASSIGN(pvn_pr); + ASSIGN(pvnr_cred); + vattr_to_50(&omsg->pvnr_va, &cmsg->pvnr_va); + + break; + } + case PUFFS_VN_GETATTR: + { + INIT(vnmsg_getattr); + + ASSIGN(pvn_pr); + ASSIGN(pvnr_cred); + + break; + } + + default: + break; + } + } + + if (creq) { + *creqp = creq; + *deltap = delta; + rv = true; + } + + return rv; +} +#undef INIT +#undef ASSIGN + +#define INIT(name) \ + struct puffs50_##name *cmsg = (void *)preq; \ + struct puffs_##name *omsg = (void *)creq; +#define ASSIGN(field) \ + omsg->field = cmsg->field; + +void +puffs_compat_incoming(struct puffs_req *preq, struct puffs_req *creq) +{ + + if (PUFFSOP_OPCLASS(preq->preq_opclass == PUFFSOP_VFS)) { + INIT(vfsmsg_fhtonode); + + ASSIGN(pvfsr_pr); + + ASSIGN(pvfsr_fhcookie); + ASSIGN(pvfsr_vtype); + ASSIGN(pvfsr_size); + ASSIGN(pvfsr_rdev); + } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN) { + switch (preq->preq_optype) { + case PUFFS_VN_LOOKUP: + { + INIT(vnmsg_lookup); + + ASSIGN(pvn_pr); + ASSIGN(pvnr_newnode); + ASSIGN(pvnr_vtype); + ASSIGN(pvnr_size); + ASSIGN(pvnr_rdev); + + break; + } + + case PUFFS_VN_CREATE: + { + INIT(vnmsg_create); + + ASSIGN(pvn_pr); + ASSIGN(pvnr_newnode); + + break; + } + + case PUFFS_VN_MKNOD: + { + INIT(vnmsg_mknod); + + ASSIGN(pvn_pr); + ASSIGN(pvnr_newnode); + + break; + } + + case PUFFS_VN_MKDIR: + { + INIT(vnmsg_mkdir); + + ASSIGN(pvn_pr); + ASSIGN(pvnr_newnode); + + break; + } + + case PUFFS_VN_SYMLINK: + { + INIT(vnmsg_symlink); + + ASSIGN(pvn_pr); + ASSIGN(pvnr_newnode); + + break; + } + + case PUFFS_VN_SETATTR: + { + INIT(vnmsg_setattr); + + ASSIGN(pvn_pr); + + break; + } + case PUFFS_VN_GETATTR: + { + INIT(vnmsg_getattr); + + ASSIGN(pvn_pr); + vattr_from_50(&cmsg->pvnr_va, &omsg->pvnr_va); + + break; + } + + default: + panic("puffs compat ops come in pairs"); + } + } +} diff --git a/sys/fs/puffs/puffs_msgif.c b/sys/fs/puffs/puffs_msgif.c index 2e7b692f1cf6..4c064e71b099 100644 --- a/sys/fs/puffs/puffs_msgif.c +++ b/sys/fs/puffs/puffs_msgif.c @@ -1,4 +1,4 @@ -/* $NetBSD: puffs_msgif.c,v 1.80 2010/01/14 19:50:07 pooka Exp $ */ +/* $NetBSD: puffs_msgif.c,v 1.81 2010/07/06 13:47:47 pooka Exp $ */ /* * Copyright (c) 2005, 2006, 2007 Antti Kantee. All Rights Reserved. @@ -30,7 +30,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: puffs_msgif.c,v 1.80 2010/01/14 19:50:07 pooka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: puffs_msgif.c,v 1.81 2010/07/06 13:47:47 pooka Exp $"); #include #include @@ -65,6 +65,9 @@ struct puffs_msgpark { size_t park_copylen; /* userspace copylength */ size_t park_maxlen; /* max size in comeback */ + struct puffs_req *park_creq; /* non-compat preq */ + size_t park_creqlen; /* non-compat preq len */ + parkdone_fn park_done; /* "biodone" a'la puffs */ void *park_donearg; @@ -136,7 +139,7 @@ puffs_msgpark_alloc(int waitok) return park; park->park_refcount = 1; - park->park_preq = NULL; + park->park_preq = park->park_creq = NULL; park->park_flags = PARKFLAG_WANTREPLY; #ifdef PUFFSDEBUG @@ -161,6 +164,7 @@ static void puffs_msgpark_release1(struct puffs_msgpark *park, int howmany) { struct puffs_req *preq = park->park_preq; + struct puffs_req *creq = park->park_creq; int refcnt; KASSERT(mutex_owned(&park->park_mtx)); @@ -173,6 +177,10 @@ puffs_msgpark_release1(struct puffs_msgpark *park, int howmany) alloced--; if (preq) kmem_free(preq, park->park_maxlen); +#if 1 + if (creq) + kmem_free(creq, park->park_creqlen); +#endif pool_cache_put(parkpc, park); #ifdef PUFFSDEBUG @@ -324,10 +332,24 @@ puffs_msg_enqueue(struct puffs_mount *pmp, struct puffs_msgpark *park) { struct lwp *l = curlwp; struct mount *mp; - struct puffs_req *preq; + struct puffs_req *preq, *creq; + ssize_t delta; mp = PMPTOMP(pmp); preq = park->park_preq; + +#if 1 + /* check if we do compat adjustments */ + if (pmp->pmp_docompat && puffs_compat_outgoing(preq, &creq, &delta)) { + park->park_creq = park->park_preq; + park->park_creqlen = park->park_maxlen; + + park->park_maxlen += delta; + park->park_copylen += delta; + park->park_preq = preq = creq; + } +#endif + preq->preq_buflen = park->park_maxlen; KASSERT(preq->preq_id == 0 || (preq->preq_opclass & PUFFSOPFLAG_ISRESPONSE)); @@ -732,13 +754,31 @@ puffsop_msg(void *this, struct puffs_req *preq) DPRINTF(("puffsop_msg: bad service - waiter gone for " "park %p\n", park)); } else { +#if 1 + if (park->park_creq) { + struct puffs_req *creq; + size_t csize; + + KASSERT(pmp->pmp_docompat); + puffs_compat_incoming(preq, park->park_creq); + creq = park->park_creq; + csize = park->park_creqlen; + park->park_creq = park->park_preq; + park->park_creqlen = park->park_maxlen; + + park->park_preq = creq; + park->park_maxlen = csize; + + memcpy(park->park_creq, preq, pth->pth_framelen); + } else { +#endif + memcpy(park->park_preq, preq, pth->pth_framelen); + } + if (park->park_flags & PARKFLAG_CALL) { DPRINTF(("puffsop_msg: call for %p, arg %p\n", park->park_preq, park->park_donearg)); park->park_done(pmp, preq, park->park_donearg); - } else { - /* XXX: yes, I know */ - memcpy(park->park_preq, preq, pth->pth_framelen); } } diff --git a/sys/fs/puffs/puffs_msgif.h b/sys/fs/puffs/puffs_msgif.h index a8fd23097a1a..9be62f8b63b9 100644 --- a/sys/fs/puffs/puffs_msgif.h +++ b/sys/fs/puffs/puffs_msgif.h @@ -1,4 +1,4 @@ -/* $NetBSD: puffs_msgif.h,v 1.74 2010/06/07 11:21:31 pooka Exp $ */ +/* $NetBSD: puffs_msgif.h,v 1.75 2010/07/06 13:47:47 pooka Exp $ */ /* * Copyright (c) 2005, 2006, 2007 Antti Kantee. All Rights Reserved. @@ -146,7 +146,9 @@ struct puffs_kargs { struct statvfs pa_svfsb; - uint32_t pa_spare[128]; + uint32_t pa_time32; + + uint32_t pa_spare[127]; }; #define pa_root_rdev devunion.dev diff --git a/sys/fs/puffs/puffs_sys.h b/sys/fs/puffs/puffs_sys.h index 6d612832e09b..9ab58d71ce78 100644 --- a/sys/fs/puffs/puffs_sys.h +++ b/sys/fs/puffs/puffs_sys.h @@ -1,4 +1,4 @@ -/* $NetBSD: puffs_sys.h,v 1.75 2010/01/07 23:02:34 pooka Exp $ */ +/* $NetBSD: puffs_sys.h,v 1.76 2010/07/06 13:47:47 pooka Exp $ */ /* * Copyright (c) 2005, 2006 Antti Kantee. All Rights Reserved. @@ -166,6 +166,7 @@ struct puffs_mount { kcondvar_t pmp_sopcv; int pmp_sopthrcount; TAILQ_HEAD(, puffs_sopreq) pmp_sopreqs; + bool pmp_docompat; }; #define PUFFSTAT_BEFOREINIT 0 @@ -263,6 +264,9 @@ void puffs_gop_markupdate(struct vnode *, int); void puffs_senderr(struct puffs_mount *, int, int, const char *, puffs_cookie_t); +bool puffs_compat_outgoing(struct puffs_req *, struct puffs_req**, ssize_t*); +void puffs_compat_incoming(struct puffs_req *, struct puffs_req *); + void puffs_updatenode(struct puffs_node *, int, voff_t); #define PUFFS_UPDATEATIME 0x01 #define PUFFS_UPDATECTIME 0x02 diff --git a/sys/fs/puffs/puffs_vfsops.c b/sys/fs/puffs/puffs_vfsops.c index 6949ecb840e1..2fb009274d42 100644 --- a/sys/fs/puffs/puffs_vfsops.c +++ b/sys/fs/puffs/puffs_vfsops.c @@ -1,4 +1,4 @@ -/* $NetBSD: puffs_vfsops.c,v 1.92 2010/07/06 12:28:40 pooka Exp $ */ +/* $NetBSD: puffs_vfsops.c,v 1.93 2010/07/06 13:47:47 pooka Exp $ */ /* * Copyright (c) 2005, 2006 Antti Kantee. All Rights Reserved. @@ -30,7 +30,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: puffs_vfsops.c,v 1.92 2010/07/06 12:28:40 pooka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: puffs_vfsops.c,v 1.93 2010/07/06 13:47:47 pooka Exp $"); #include #include @@ -292,6 +292,7 @@ puffs_vfsop_mount(struct mount *mp, const char *path, void *data, pmp->pmp_root_vtype = args->pa_root_vtype; pmp->pmp_root_vsize = args->pa_root_vsize; pmp->pmp_root_rdev = args->pa_root_rdev; + pmp->pmp_docompat = args->pa_time32; mutex_init(&pmp->pmp_lock, MUTEX_DEFAULT, IPL_NONE); mutex_init(&pmp->pmp_sopmtx, MUTEX_DEFAULT, IPL_NONE);