Home | History | Annotate | Line # | Download | only in coda
coda_venus.c revision 1.28
      1 /*	$NetBSD: coda_venus.c,v 1.28 2010/07/20 17:26:03 christos Exp $	*/
      2 
      3 /*
      4  *
      5  *             Coda: an Experimental Distributed File System
      6  *                              Release 3.1
      7  *
      8  *           Copyright (c) 1987-1998 Carnegie Mellon University
      9  *                          All Rights Reserved
     10  *
     11  * Permission  to  use, copy, modify and distribute this software and its
     12  * documentation is hereby granted,  provided  that  both  the  copyright
     13  * notice  and  this  permission  notice  appear  in  all  copies  of the
     14  * software, derivative works or  modified  versions,  and  any  portions
     15  * thereof, and that both notices appear in supporting documentation, and
     16  * that credit is given to Carnegie Mellon University  in  all  documents
     17  * and publicity pertaining to direct or indirect use of this code or its
     18  * derivatives.
     19  *
     20  * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS  KNOWN  TO  HAVE  BUGS,
     21  * SOME  OF  WHICH MAY HAVE SERIOUS CONSEQUENCES.  CARNEGIE MELLON ALLOWS
     22  * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.   CARNEGIE  MELLON
     23  * DISCLAIMS  ANY  LIABILITY  OF  ANY  KIND  FOR  ANY  DAMAGES WHATSOEVER
     24  * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE  OR  OF
     25  * ANY DERIVATIVE WORK.
     26  *
     27  * Carnegie  Mellon  encourages  users  of  this  software  to return any
     28  * improvements or extensions that  they  make,  and  to  grant  Carnegie
     29  * Mellon the rights to redistribute these changes without encumbrance.
     30  *
     31  * 	@(#) coda/coda_venus.c,v 1.1.1.1 1998/08/29 21:26:45 rvb Exp $
     32  */
     33 
     34 #include <sys/cdefs.h>
     35 __KERNEL_RCSID(0, "$NetBSD: coda_venus.c,v 1.28 2010/07/20 17:26:03 christos Exp $");
     36 
     37 #include <sys/param.h>
     38 #include <sys/systm.h>
     39 #include <sys/malloc.h>
     40 #include <sys/proc.h>
     41 #include <sys/select.h>
     42 #include <sys/ioctl.h>
     43 /* for CNV_OFLAGS below */
     44 #include <sys/fcntl.h>
     45 #include <sys/kauth.h>
     46 
     47 #include <coda/coda.h>
     48 #include <coda/cnode.h>
     49 #include <coda/coda_venus.h>
     50 #include <coda/coda_pioctl.h>
     51 
     52 #ifdef _KERNEL_OPT
     53 #include "opt_coda_compat.h"
     54 #endif
     55 
     56 /*
     57  * Isize and Osize are the sizes of the input and output arguments.
     58  * SEMI-INVARIANT: name##_size (e.g. coda_readlink_size) is the max of
     59  * the input and output.  This invariant is not well maintained, but
     60  * should be true after ALLOC_*.  Isize is modified after allocation
     61  * by STRCPY below - this is in general unsafe and needs fixing.
     62  */
     63 
     64 #define DECL_NO_IN(name) 				\
     65     struct coda_in_hdr *inp;				\
     66     struct name ## _out *outp;				\
     67     int name ## _size = sizeof (struct coda_in_hdr);	\
     68     int Isize = sizeof (struct coda_in_hdr);		\
     69     int Osize = sizeof (struct name ## _out);		\
     70     int error
     71 
     72 #define DECL(name)					\
     73     struct name ## _in *inp;				\
     74     struct name ## _out *outp;				\
     75     int name ## _size = sizeof (struct name ## _in);	\
     76     int Isize = sizeof (struct name ## _in);		\
     77     int Osize = sizeof (struct name ## _out);		\
     78     int error
     79 
     80 #define DECL_NO_OUT(name)				\
     81     struct name ## _in *inp;				\
     82     struct coda_out_hdr *outp;				\
     83     int name ## _size = sizeof (struct name ## _in);	\
     84     int Isize = sizeof (struct name ## _in);		\
     85     int Osize = sizeof (struct coda_out_hdr);		\
     86     int error
     87 
     88 #define ALLOC_NO_IN(name)				\
     89     if (Osize > name ## _size)				\
     90     	name ## _size = Osize;				\
     91     CODA_ALLOC(inp, struct coda_in_hdr *, name ## _size);\
     92     outp = (struct name ## _out *) inp
     93 
     94 #define ALLOC(name)					\
     95     if (Osize > name ## _size)				\
     96     	name ## _size = Osize;				\
     97     CODA_ALLOC(inp, struct name ## _in *, name ## _size);\
     98     outp = (struct name ## _out *) inp
     99 
    100 #define ALLOC_NO_OUT(name)				\
    101     if (Osize > name ## _size)				\
    102     	name ## _size = Osize;				\
    103     CODA_ALLOC(inp, struct name ## _in *, name ## _size);\
    104     outp = (struct coda_out_hdr *) inp
    105 
    106 #define STRCPY(struc, name, len) \
    107     memcpy((char *)inp + (int)inp->struc, name, len); \
    108     ((char*)inp + (int)inp->struc)[len++] = 0; \
    109     Isize += len
    110 /* XXX verify that Isize has not overrun available storage */
    111 
    112 #ifdef CODA_COMPAT_5
    113 
    114 #define INIT_IN(in, op, ident, p) \
    115 	  (in)->opcode = (op); \
    116 	  (in)->pid = p ? p->p_pid : -1; \
    117           (in)->pgid = p ? p->p_pgid : -1; \
    118           (in)->sid = (p && p->p_session && p->p_session->s_leader) ? \
    119 		(p->p_session->s_leader->p_pid) : -1; \
    120 	  KASSERT(cred != NULL); \
    121 	  KASSERT(cred != FSCRED); \
    122           if (ident != NOCRED) {                              \
    123 	      (in)->cred.cr_uid = kauth_cred_geteuid(ident);              \
    124 	      (in)->cred.cr_groupid = kauth_cred_getegid(ident);          \
    125           } else {                                            \
    126 	      memset(&((in)->cred), 0, sizeof(struct coda_cred)); \
    127 	      (in)->cred.cr_uid = -1;                         \
    128 	      (in)->cred.cr_groupid = -1;                     \
    129           }                                                   \
    130 
    131 #else
    132 
    133 #define INIT_IN(in, op, ident, p) 		\
    134 	  (in)->opcode = (op); 			\
    135 	  (in)->pid = p ? p->p_pid : -1;        \
    136           (in)->pgid = p ? p->p_pgid : -1;	\
    137 	  KASSERT(cred != NULL); \
    138 	  KASSERT(cred != FSCRED); \
    139           if (ident != NOCRED) {                \
    140 	      (in)->uid = kauth_cred_geteuid(ident);        \
    141           } else {                              \
    142 	      (in)->uid = -1;                   \
    143           }                                                   \
    144 
    145 #endif
    146 
    147 #define INIT_IN_L(in, op, ident, l)		\
    148 	INIT_IN(in, op, ident, (l ? l->l_proc : NULL))
    149 
    150 #define	CNV_OFLAG(to, from) 				\
    151     do { 						\
    152 	  to = 0;					\
    153 	  if (from & FREAD)   to |= C_O_READ; 		\
    154 	  if (from & FWRITE)  to |= C_O_WRITE; 		\
    155 	  if (from & O_TRUNC) to |= C_O_TRUNC; 		\
    156 	  if (from & O_EXCL)  to |= C_O_EXCL; 		\
    157 	  if (from & O_CREAT) to |= C_O_CREAT;		\
    158     } while (/*CONSTCOND*/ 0)
    159 
    160 #define CNV_VV2V_ATTR(top, fromp) \
    161 	do { \
    162 		(top)->va_type = (fromp)->va_type; \
    163 		(top)->va_mode = (fromp)->va_mode; \
    164 		(top)->va_nlink = (fromp)->va_nlink; \
    165 		(top)->va_uid = (fromp)->va_uid; \
    166 		(top)->va_gid = (fromp)->va_gid; \
    167 		(top)->va_fsid = VNOVAL; \
    168 		(top)->va_fileid = (fromp)->va_fileid; \
    169 		(top)->va_size = (fromp)->va_size; \
    170 		(top)->va_blocksize = (fromp)->va_blocksize; \
    171 		(top)->va_atime = (fromp)->va_atime; \
    172 		(top)->va_mtime = (fromp)->va_mtime; \
    173 		(top)->va_ctime = (fromp)->va_ctime; \
    174 		(top)->va_gen = (fromp)->va_gen; \
    175 		(top)->va_flags = (fromp)->va_flags; \
    176 		(top)->va_rdev = (fromp)->va_rdev; \
    177 		(top)->va_bytes = (fromp)->va_bytes; \
    178 		(top)->va_filerev = (fromp)->va_filerev; \
    179 		(top)->va_vaflags = VNOVAL; \
    180 		(top)->va_spare = VNOVAL; \
    181 	} while (/*CONSTCOND*/ 0)
    182 
    183 #define CNV_V2VV_ATTR(top, fromp) \
    184 	do { \
    185 		(top)->va_type = (fromp)->va_type; \
    186 		(top)->va_mode = (fromp)->va_mode; \
    187 		(top)->va_nlink = (fromp)->va_nlink; \
    188 		(top)->va_uid = (fromp)->va_uid; \
    189 		(top)->va_gid = (fromp)->va_gid; \
    190 		(top)->va_fileid = (fromp)->va_fileid; \
    191 		(top)->va_size = (fromp)->va_size; \
    192 		(top)->va_blocksize = (fromp)->va_blocksize; \
    193 		(top)->va_atime = (fromp)->va_atime; \
    194 		(top)->va_mtime = (fromp)->va_mtime; \
    195 		(top)->va_ctime = (fromp)->va_ctime; \
    196 		(top)->va_gen = (fromp)->va_gen; \
    197 		(top)->va_flags = (fromp)->va_flags; \
    198 		(top)->va_rdev = (fromp)->va_rdev; \
    199 		(top)->va_bytes = (fromp)->va_bytes; \
    200 		(top)->va_filerev = (fromp)->va_filerev; \
    201 	} while (/*CONSTCOND*/ 0)
    202 
    203 
    204 int coda_kernel_version = CODA_KERNEL_VERSION;
    205 
    206 int
    207 venus_root(void *mdp,
    208 	kauth_cred_t cred, struct proc *p,
    209 /*out*/	CodaFid *VFid)
    210 {
    211     DECL_NO_IN(coda_root);		/* sets Isize & Osize */
    212     ALLOC_NO_IN(coda_root);		/* sets inp & outp */
    213 
    214     /* send the open to venus. */
    215     INIT_IN(inp, CODA_ROOT, cred, p);
    216 
    217     error = coda_call(mdp, Isize, &Osize, (char *)inp);
    218     if (!error)
    219 	*VFid = outp->Fid;
    220 
    221     CODA_FREE(inp, coda_root_size);
    222     return error;
    223 }
    224 
    225 int
    226 venus_open(void *mdp, CodaFid *fid, int flag,
    227 	kauth_cred_t cred, struct lwp *l,
    228 /*out*/	dev_t *dev, ino_t *inode)
    229 {
    230     int cflag;
    231     DECL(coda_open);			/* sets Isize & Osize */
    232     ALLOC(coda_open);			/* sets inp & outp */
    233 
    234     /* send the open to venus. */
    235     INIT_IN_L(&inp->ih, CODA_OPEN, cred, l);
    236     inp->Fid = *fid;
    237     CNV_OFLAG(cflag, flag);
    238     inp->flags = cflag;
    239 
    240     error = coda_call(mdp, Isize, &Osize, (char *)inp);
    241     KASSERT(outp != NULL);
    242     if (!error) {
    243 	*dev =  outp->dev;
    244 	*inode = outp->inode;
    245     }
    246 
    247     CODA_FREE(inp, coda_open_size);
    248     return error;
    249 }
    250 
    251 int
    252 venus_close(void *mdp, CodaFid *fid, int flag,
    253 	kauth_cred_t cred, struct lwp *l)
    254 {
    255     int cflag;
    256     DECL_NO_OUT(coda_close);		/* sets Isize & Osize */
    257     ALLOC_NO_OUT(coda_close);		/* sets inp & outp */
    258 
    259     INIT_IN_L(&inp->ih, CODA_CLOSE, cred, l);
    260     inp->Fid = *fid;
    261     CNV_OFLAG(cflag, flag);
    262     inp->flags = cflag;
    263 
    264     error = coda_call(mdp, Isize, &Osize, (char *)inp);
    265 
    266     CODA_FREE(inp, coda_close_size);
    267     return error;
    268 }
    269 
    270 /*
    271  * these two calls will not exist!!!  the container file is read/written
    272  * directly.
    273  */
    274 void
    275 venus_read(void)
    276 {
    277 }
    278 
    279 void
    280 venus_write(void)
    281 {
    282 }
    283 
    284 /*
    285  * this is a bit sad too.  the ioctl's are for the control file, not for
    286  * normal files.
    287  */
    288 int
    289 venus_ioctl(void *mdp, CodaFid *fid,
    290 	int com, int flag, void *data,
    291 	kauth_cred_t cred, struct lwp *l)
    292 {
    293     DECL(coda_ioctl);			/* sets Isize & Osize */
    294     struct PioctlData *iap = (struct PioctlData *)data;
    295     int tmp;
    296 
    297     coda_ioctl_size = VC_MAXMSGSIZE;
    298     ALLOC(coda_ioctl);			/* sets inp & outp */
    299 
    300     INIT_IN_L(&inp->ih, CODA_IOCTL, cred, l);
    301     inp->Fid = *fid;
    302 
    303     /* command was mutated by increasing its size field to reflect the
    304      * path and follow args. we need to subtract that out before sending
    305      * the command to venus.
    306      */
    307     inp->cmd = (com & ~(IOCPARM_MASK << 16));
    308     tmp = ((com >> 16) & IOCPARM_MASK) - sizeof (char *) - sizeof (int);
    309     inp->cmd |= (tmp & IOCPARM_MASK) <<	16;
    310 
    311     if (iap->vi.in_size > VC_MAXMSGSIZE || iap->vi.out_size > VC_MAXMSGSIZE) {
    312 	CODA_FREE(inp, coda_ioctl_size);
    313 	return (EINVAL);
    314     }
    315 
    316     inp->rwflag = flag;
    317     inp->len = iap->vi.in_size;
    318     inp->data = (char *)(sizeof (struct coda_ioctl_in));
    319 
    320     error = copyin(iap->vi.in, (char*)inp + (int)(long)inp->data,
    321 		   iap->vi.in_size);
    322     if (error) {
    323 	CODA_FREE(inp, coda_ioctl_size);
    324 	return(error);
    325     }
    326 
    327     Osize = VC_MAXMSGSIZE;
    328     error = coda_call(mdp, Isize + iap->vi.in_size, &Osize, (char *)inp);
    329 
    330 	/* copy out the out buffer. */
    331     if (!error) {
    332 	if (outp->len > iap->vi.out_size) {
    333 	    error = EINVAL;
    334 	} else {
    335 	    error = copyout((char *)outp + (int)(long)outp->data,
    336 			    iap->vi.out, iap->vi.out_size);
    337 	}
    338     }
    339 
    340     CODA_FREE(inp, coda_ioctl_size);
    341     return error;
    342 }
    343 
    344 int
    345 venus_getattr(void *mdp, CodaFid *fid,
    346 	kauth_cred_t cred, struct lwp *l,
    347 /*out*/	struct vattr *vap)
    348 {
    349     DECL(coda_getattr);			/* sets Isize & Osize */
    350     ALLOC(coda_getattr);			/* sets inp & outp */
    351 
    352     /* send the open to venus. */
    353     INIT_IN_L(&inp->ih, CODA_GETATTR, cred, l);
    354     inp->Fid = *fid;
    355 
    356     error = coda_call(mdp, Isize, &Osize, (char *)inp);
    357     if (!error) {
    358 	CNV_VV2V_ATTR(vap, &outp->attr);
    359     }
    360 
    361     CODA_FREE(inp, coda_getattr_size);
    362     return error;
    363 }
    364 
    365 int
    366 venus_setattr(void *mdp, CodaFid *fid, struct vattr *vap,
    367 	kauth_cred_t cred, struct lwp *l)
    368 {
    369     DECL_NO_OUT(coda_setattr);		/* sets Isize & Osize */
    370     ALLOC_NO_OUT(coda_setattr);		/* sets inp & outp */
    371 
    372     /* send the open to venus. */
    373     INIT_IN_L(&inp->ih, CODA_SETATTR, cred, l);
    374     inp->Fid = *fid;
    375     CNV_V2VV_ATTR(&inp->attr, vap);
    376 
    377     error = coda_call(mdp, Isize, &Osize, (char *)inp);
    378 
    379     CODA_FREE(inp, coda_setattr_size);
    380     return error;
    381 }
    382 
    383 int
    384 venus_access(void *mdp, CodaFid *fid, int mode,
    385 	kauth_cred_t cred, struct lwp *l)
    386 {
    387     DECL_NO_OUT(coda_access);		/* sets Isize & Osize */
    388     ALLOC_NO_OUT(coda_access);		/* sets inp & outp */
    389 
    390     /* send the open to venus. */
    391     INIT_IN_L(&inp->ih, CODA_ACCESS, cred, l);
    392     inp->Fid = *fid;
    393     inp->flags = mode;
    394 
    395     error = coda_call(mdp, Isize, &Osize, (char *)inp);
    396 
    397     CODA_FREE(inp, coda_access_size);
    398     return error;
    399 }
    400 
    401 int
    402 venus_readlink(void *mdp, CodaFid *fid,
    403 	kauth_cred_t cred, struct lwp *l,
    404 /*out*/	char **str, int *len)
    405 {
    406     DECL(coda_readlink);			/* sets Isize & Osize */
    407     /* XXX coda_readlink_size should not be set here */
    408     coda_readlink_size += CODA_MAXPATHLEN;
    409     Osize += CODA_MAXPATHLEN;
    410     ALLOC(coda_readlink);		/* sets inp & outp */
    411 
    412     /* send the open to venus. */
    413     INIT_IN_L(&inp->ih, CODA_READLINK, cred, l);
    414     inp->Fid = *fid;
    415 
    416     error = coda_call(mdp, Isize, &Osize, (char *)inp);
    417     KASSERT(outp != NULL);
    418     if (error != 0)
    419 	    goto out;
    420 
    421     /* Check count for reasonableness */
    422     if (outp->count <= 0 || outp->count > CODA_MAXPATHLEN) {
    423 	    printf("venus_readlink: bad count %d\n", outp->count);
    424 	    error = EINVAL;
    425 	    goto out;
    426     }
    427 
    428     /*
    429      * Check data pointer for reasonableness.  It must point after
    430      * itself, and within the allocated region.
    431      */
    432     if ((intptr_t) outp->data < sizeof(struct coda_readlink_out) ) {
    433 	    printf("venus_readlink: data pointer %lld too low\n",
    434 		   (long long)((intptr_t) outp->data));
    435 	    error = EINVAL;
    436 	    goto out;
    437     }
    438 
    439     if ((intptr_t) outp->data + outp->count >
    440 	sizeof(struct coda_readlink_out) + CODA_MAXPATHLEN) {
    441 	    printf("venus_readlink: data pointer %lld too high\n",
    442 		   (long long)((intptr_t) outp->data));
    443 	    error = EINVAL;
    444 	    goto out;
    445     }
    446 
    447     if (!error) {
    448 	    CODA_ALLOC(*str, char *, outp->count);
    449 	    *len = outp->count;
    450 	    memcpy(*str, (char *)outp + (int)(long)outp->data, *len);
    451     }
    452 
    453 out:
    454     CODA_FREE(inp, coda_readlink_size);
    455     return error;
    456 }
    457 
    458 int
    459 venus_fsync(void *mdp, CodaFid *fid,
    460 	kauth_cred_t cred, struct lwp *l)
    461 {
    462     DECL_NO_OUT(coda_fsync);		/* sets Isize & Osize */
    463     ALLOC_NO_OUT(coda_fsync);		/* sets inp & outp */
    464 
    465     /* send the open to venus. */
    466     INIT_IN_L(&inp->ih, CODA_FSYNC, cred, l);
    467     inp->Fid = *fid;
    468 
    469     error = coda_call(mdp, Isize, &Osize, (char *)inp);
    470 
    471     CODA_FREE(inp, coda_fsync_size);
    472     return error;
    473 }
    474 
    475 int
    476 venus_lookup(void *mdp, CodaFid *fid,
    477     	const char *nm, int len,
    478 	kauth_cred_t cred, struct lwp *l,
    479 /*out*/	CodaFid *VFid, int *vtype)
    480 {
    481     DECL(coda_lookup);			/* sets Isize & Osize */
    482     coda_lookup_size += len + 1;
    483     ALLOC(coda_lookup);			/* sets inp & outp */
    484 
    485     /* send the open to venus. */
    486     INIT_IN_L(&inp->ih, CODA_LOOKUP, cred, l);
    487     inp->Fid = *fid;
    488 
    489     /* NOTE:
    490      * Between version 1 and version 2 we have added an extra flag field
    491      * to this structure.  But because the string was at the end and because
    492      * of the weird way we represent strings by having the slot point to
    493      * where the string characters are in the "heap", we can just slip the
    494      * flag parameter in after the string slot pointer and veni that don't
    495      * know better won't see this new flag field ...
    496      * Otherwise we'd need two different venus_lookup functions.
    497      */
    498     inp->name = Isize;
    499     inp->flags = CLU_CASE_SENSITIVE;	/* doesn't really matter for BSD */
    500     /* This is safe because we preallocated len+1 extra. */
    501     STRCPY(name, nm, len);		/* increments Isize */
    502 
    503     error = coda_call(mdp, Isize, &Osize, (char *)inp);
    504     KASSERT(outp != NULL);
    505     if (!error) {
    506 	*VFid = outp->Fid;
    507 	*vtype = outp->vtype;
    508     }
    509 
    510     CODA_FREE(inp, coda_lookup_size);
    511     return error;
    512 }
    513 
    514 int
    515 venus_create(void *mdp, CodaFid *fid,
    516     	const char *nm, int len, int exclusive, int mode, struct vattr *va,
    517 	kauth_cred_t cred, struct lwp *l,
    518 /*out*/	CodaFid *VFid, struct vattr *attr)
    519 {
    520     DECL(coda_create);			/* sets Isize & Osize */
    521     coda_create_size += len + 1;
    522     ALLOC(coda_create);			/* sets inp & outp */
    523 
    524     /* send the open to venus. */
    525     INIT_IN_L(&inp->ih, CODA_CREATE, cred, l);
    526     inp->Fid = *fid;
    527     inp->excl = exclusive ? C_O_EXCL : 0;
    528     inp->mode = mode<<6;
    529     CNV_V2VV_ATTR(&inp->attr, va);
    530 
    531     inp->name = Isize;
    532     STRCPY(name, nm, len);		/* increments Isize */
    533 
    534     error = coda_call(mdp, Isize, &Osize, (char *)inp);
    535     KASSERT(outp != NULL);
    536     if (!error) {
    537 	*VFid = outp->Fid;
    538 	CNV_VV2V_ATTR(attr, &outp->attr);
    539     }
    540 
    541     CODA_FREE(inp, coda_create_size);
    542     return error;
    543 }
    544 
    545 int
    546 venus_remove(void *mdp, CodaFid *fid,
    547         const char *nm, int len,
    548 	kauth_cred_t cred, struct lwp *l)
    549 {
    550     DECL_NO_OUT(coda_remove);		/* sets Isize & Osize */
    551     coda_remove_size += len + 1;
    552     ALLOC_NO_OUT(coda_remove);		/* sets inp & outp */
    553 
    554     /* send the open to venus. */
    555     INIT_IN_L(&inp->ih, CODA_REMOVE, cred, l);
    556     inp->Fid = *fid;
    557 
    558     inp->name = Isize;
    559     STRCPY(name, nm, len);		/* increments Isize */
    560 
    561     error = coda_call(mdp, Isize, &Osize, (char *)inp);
    562 
    563     CODA_FREE(inp, coda_remove_size);
    564     return error;
    565 }
    566 
    567 int
    568 venus_link(void *mdp, CodaFid *fid, CodaFid *tfid,
    569         const char *nm, int len,
    570 	kauth_cred_t cred, struct lwp *l)
    571 {
    572     DECL_NO_OUT(coda_link);		/* sets Isize & Osize */
    573     coda_link_size += len + 1;
    574     ALLOC_NO_OUT(coda_link);		/* sets inp & outp */
    575 
    576     /* send the open to venus. */
    577     INIT_IN_L(&inp->ih, CODA_LINK, cred, l);
    578     inp->sourceFid = *fid;
    579     inp->destFid = *tfid;
    580 
    581     inp->tname = Isize;
    582     STRCPY(tname, nm, len);		/* increments Isize */
    583 
    584     error = coda_call(mdp, Isize, &Osize, (char *)inp);
    585 
    586     CODA_FREE(inp, coda_link_size);
    587     return error;
    588 }
    589 
    590 int
    591 venus_rename(void *mdp, CodaFid *fid, CodaFid *tfid,
    592         const char *nm, int len, const char *tnm, int tlen,
    593 	kauth_cred_t cred, struct lwp *l)
    594 {
    595     DECL_NO_OUT(coda_rename);		/* sets Isize & Osize */
    596     coda_rename_size += len + 1 + tlen + 1;
    597     ALLOC_NO_OUT(coda_rename);		/* sets inp & outp */
    598 
    599     /* send the open to venus. */
    600     INIT_IN_L(&inp->ih, CODA_RENAME, cred, l);
    601     inp->sourceFid = *fid;
    602     inp->destFid = *tfid;
    603 
    604     inp->srcname = Isize;
    605     STRCPY(srcname, nm, len);		/* increments Isize */
    606 
    607     inp->destname = Isize;
    608     STRCPY(destname, tnm, tlen);	/* increments Isize */
    609 
    610     error = coda_call(mdp, Isize, &Osize, (char *)inp);
    611 
    612     CODA_FREE(inp, coda_rename_size);
    613     return error;
    614 }
    615 
    616 int
    617 venus_mkdir(void *mdp, CodaFid *fid,
    618     	const char *nm, int len, struct vattr *va,
    619 	kauth_cred_t cred, struct lwp *l,
    620 /*out*/	CodaFid *VFid, struct vattr *ova)
    621 {
    622     DECL(coda_mkdir);			/* sets Isize & Osize */
    623     coda_mkdir_size += len + 1;
    624     ALLOC(coda_mkdir);			/* sets inp & outp */
    625 
    626     /* send the open to venus. */
    627     INIT_IN_L(&inp->ih, CODA_MKDIR, cred, l);
    628     inp->Fid = *fid;
    629     CNV_V2VV_ATTR(&inp->attr, va);
    630 
    631     inp->name = Isize;
    632     STRCPY(name, nm, len);		/* increments Isize */
    633 
    634     error = coda_call(mdp, Isize, &Osize, (char *)inp);
    635     KASSERT(outp != NULL);
    636     if (!error) {
    637 	*VFid = outp->Fid;
    638 	CNV_VV2V_ATTR(ova, &outp->attr);
    639     }
    640 
    641     CODA_FREE(inp, coda_mkdir_size);
    642     return error;
    643 }
    644 
    645 int
    646 venus_rmdir(void *mdp, CodaFid *fid,
    647     	const char *nm, int len,
    648 	kauth_cred_t cred, struct lwp *l)
    649 {
    650     DECL_NO_OUT(coda_rmdir);		/* sets Isize & Osize */
    651     coda_rmdir_size += len + 1;
    652     ALLOC_NO_OUT(coda_rmdir);		/* sets inp & outp */
    653 
    654     /* send the open to venus. */
    655     INIT_IN_L(&inp->ih, CODA_RMDIR, cred, l);
    656     inp->Fid = *fid;
    657 
    658     inp->name = Isize;
    659     STRCPY(name, nm, len);		/* increments Isize */
    660 
    661     error = coda_call(mdp, Isize, &Osize, (char *)inp);
    662 
    663     CODA_FREE(inp, coda_rmdir_size);
    664     return error;
    665 }
    666 
    667 int
    668 venus_symlink(void *mdp, CodaFid *fid,
    669         const char *lnm, int llen, const char *nm, int len, struct vattr *va,
    670 	kauth_cred_t cred, struct lwp *l)
    671 {
    672     DECL_NO_OUT(coda_symlink);		/* sets Isize & Osize */
    673     coda_symlink_size += llen + 1 + len + 1;
    674     ALLOC_NO_OUT(coda_symlink);		/* sets inp & outp */
    675 
    676     /* send the open to venus. */
    677     INIT_IN_L(&inp->ih, CODA_SYMLINK, cred, l);
    678     inp->Fid = *fid;
    679     CNV_V2VV_ATTR(&inp->attr, va);
    680 
    681     inp->srcname = Isize;
    682     STRCPY(srcname, lnm, llen);		/* increments Isize */
    683 
    684     inp->tname = Isize;
    685     STRCPY(tname, nm, len);		/* increments Isize */
    686 
    687     error = coda_call(mdp, Isize, &Osize, (char *)inp);
    688 
    689     CODA_FREE(inp, coda_symlink_size);
    690     return error;
    691 }
    692 
    693 int
    694 venus_readdir(void *mdp, CodaFid *fid,
    695     	int count, int offset,
    696 	kauth_cred_t cred, struct lwp *l,
    697 /*out*/	char *buffer, int *len)
    698 {
    699     DECL(coda_readdir);			/* sets Isize & Osize */
    700     coda_readdir_size = VC_MAXMSGSIZE;
    701     ALLOC(coda_readdir);			/* sets inp & outp */
    702 
    703     /* send the open to venus. */
    704     INIT_IN_L(&inp->ih, CODA_READDIR, cred, l);
    705     inp->Fid = *fid;
    706     inp->count = count;
    707     inp->offset = offset;
    708 
    709     Osize = VC_MAXMSGSIZE;
    710     error = coda_call(mdp, Isize, &Osize, (char *)inp);
    711     KASSERT(outp != NULL);
    712     if (!error) {
    713 	memcpy(buffer, (char *)outp + (int)(long)outp->data, outp->size);
    714 	*len = outp->size;
    715     }
    716 
    717     CODA_FREE(inp, coda_readdir_size);
    718     return error;
    719 }
    720 
    721 int
    722 venus_statfs(void *mdp, kauth_cred_t cred, struct lwp *l,
    723    /*out*/   struct coda_statfs *fsp)
    724 {
    725     DECL(coda_statfs);			/* sets Isize & Osize */
    726     ALLOC(coda_statfs);			/* sets inp & outp */
    727 
    728     /* send the open to venus. */
    729     INIT_IN_L(&inp->ih, CODA_STATFS, cred, l);
    730 
    731     error = coda_call(mdp, Isize, &Osize, (char *)inp);
    732     KASSERT(outp != NULL);
    733     if (!error) {
    734         *fsp = outp->stat;
    735     }
    736 
    737     CODA_FREE(inp, coda_statfs_size);
    738     return error;
    739 }
    740 
    741 int
    742 venus_fhtovp(void *mdp, CodaFid *fid,
    743 	kauth_cred_t cred, struct proc *p,
    744 /*out*/	CodaFid *VFid, int *vtype)
    745 {
    746     DECL(coda_vget);			/* sets Isize & Osize */
    747     ALLOC(coda_vget);			/* sets inp & outp */
    748 
    749     /* Send the open to Venus. */
    750     INIT_IN(&inp->ih, CODA_VGET, cred, p);
    751     inp->Fid = *fid;
    752 
    753     error = coda_call(mdp, Isize, &Osize, (char *)inp);
    754     KASSERT(outp != NULL);
    755     if (!error) {
    756 	*VFid = outp->Fid;
    757 	*vtype = outp->vtype;
    758     }
    759 
    760     CODA_FREE(inp, coda_vget_size);
    761     return error;
    762 }
    763