Index: head/sys/coda/coda.h =================================================================== --- head/sys/coda/coda.h (revision 40705) +++ head/sys/coda/coda.h (revision 40706) @@ -1,677 +1,733 @@ /* * * Coda: an Experimental Distributed File System * Release 3.1 * * Copyright (c) 1987-1998 Carnegie Mellon University * All Rights Reserved * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation, and * that credit is given to Carnegie Mellon University in all documents * and publicity pertaining to direct or indirect use of this code or its * derivatives. * * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS KNOWN TO HAVE BUGS, * SOME OF WHICH MAY HAVE SERIOUS CONSEQUENCES. CARNEGIE MELLON ALLOWS * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON * DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE OR OF * ANY DERIVATIVE WORK. * * Carnegie Mellon encourages users of this software to return any * improvements or extensions that they make, and to grant Carnegie * Mellon the rights to redistribute these changes without encumbrance. * * @(#) src/sys/coda/coda.h,v 1.1.1.1 1998/08/29 21:14:52 rvb Exp $ - * $Id: coda.h,v 1.3 1998/09/11 18:50:17 rvb Exp $ + * $Id: coda.h,v 1.4 1998/09/13 13:57:59 rvb Exp $ * */ /* * * Based on cfs.h from Mach, but revamped for increased simplicity. * Linux modifications by Peter Braam, Aug 1996 */ #ifndef _CODA_HEADER_ #define _CODA_HEADER_ + + /* Catch new _KERNEL defn for NetBSD */ #ifdef __NetBSD__ #include #endif -#if defined(__linux__) || defined(__CYGWIN32__) +#ifndef CODA_MAXSYMLINKS +#define CODA_MAXSYMLINKS 10 +#endif + +#if defined(DJGPP) || defined(__CYGWIN32__) +#ifdef KERNEL +typedef unsigned long u_long; +typedef unsigned int u_int; +typedef unsigned short u_short; +typedef u_long ino_t; +typedef u_long dev_t; +typedef void * caddr_t; +typedef unsigned long long u_quad_t; + +#define inline + +struct timespec { + long ts_sec; + long ts_nsec; +}; +#else /* DJGPP but not KERNEL */ +#include +#include +typedef unsigned long long u_quad_t; +#endif /* !KERNEL */ +#endif /* !DJGPP */ + + +#if defined(__linux__) #define cdev_t u_quad_t #if !defined(_UQUAD_T_) && (!defined(__GLIBC__) || __GLIBC__ < 2) #define _UQUAD_T_ 1 typedef unsigned long long u_quad_t; -#endif +#endif #else #define cdev_t dev_t #endif #ifdef __CYGWIN32__ typedef unsigned char u_int8_t; struct timespec { time_t tv_sec; /* seconds */ long tv_nsec; /* nanoseconds */ }; #endif /* - * Coda constants + * Cfs constants */ #define CODA_MAXNAMLEN 255 #define CODA_MAXPATHLEN 1024 #define CODA_MAXSYMLINK 10 /* these are Coda's version of O_RDONLY etc combinations * to deal with VFS open modes */ #define C_O_READ 0x001 #define C_O_WRITE 0x002 #define C_O_TRUNC 0x010 #define C_O_EXCL 0x100 +#define C_O_CREAT 0x200 /* these are to find mode bits in Venus */ #define C_M_READ 00400 #define C_M_WRITE 00200 /* for access Venus will use */ +#define C_A_C_OK 8 /* Test for writing upon create. */ #define C_A_R_OK 4 /* Test for read permission. */ #define C_A_W_OK 2 /* Test for write permission. */ #define C_A_X_OK 1 /* Test for execute permission. */ #define C_A_F_OK 0 /* Test for existence. */ #ifndef _VENUS_DIRENT_T_ #define _VENUS_DIRENT_T_ 1 struct venus_dirent { unsigned long d_fileno; /* file number of entry */ unsigned short d_reclen; /* length of this record */ char d_type; /* file type, see below */ char d_namlen; /* length of string in d_name */ char d_name[CODA_MAXNAMLEN + 1];/* name must be no longer than this */ }; #undef DIRSIZ #define DIRSIZ(dp) ((sizeof (struct venus_dirent) - (CODA_MAXNAMLEN+1)) + \ (((dp)->d_namlen+1 + 3) &~ 3)) /* * File types */ #define CDT_UNKNOWN 0 -#define CDT_FIFO 1 +#define CDT_FIFO 1 #define CDT_CHR 2 #define CDT_DIR 4 #define CDT_BLK 6 #define CDT_REG 8 #define CDT_LNK 10 -#define CDT_SOCK 12 +#define CDT_SOCK 12 #define CDT_WHT 14 /* * Convert between stat structure types and directory types. */ #define IFTOCDT(mode) (((mode) & 0170000) >> 12) #define CDTTOIF(dirtype) ((dirtype) << 12) #endif #ifndef _FID_T_ #define _FID_T_ 1 typedef u_long VolumeId; typedef u_long VnodeId; typedef u_long Unique_t; typedef u_long FileVersion; #endif #ifndef _VICEFID_T_ #define _VICEFID_T_ 1 typedef struct ViceFid { VolumeId Volume; VnodeId Vnode; Unique_t Unique; } ViceFid; #endif /* VICEFID */ -#ifdef __linux__ -static inline ino_t coda_f2i(struct ViceFid *fid) + +#ifdef __linux__ +static __inline__ ino_t coda_f2i(struct ViceFid *fid) { - if ( fid ) { - return (fid->Unique + (fid->Vnode << 10) + (fid->Volume << 20)); - } else { - return 0; - } + if ( ! fid ) + return 0; + if (fid->Vnode == 0xfffffffe || fid->Vnode == 0xffffffff) + return ((fid->Volume << 20) | (fid->Unique & 0xfffff)); + else + return (fid->Unique + (fid->Vnode<<10) + (fid->Volume<<20)); } + +#else +#define coda_f2i(fid)\ + (fid) ? ((fid)->Unique + ((fid)->Vnode<<10) + ((fid)->Volume<<20)) : 0 #endif + +#ifndef __BIT_TYPES_DEFINED__ +#define u_int32_t unsigned int +#endif + + #ifndef _VUID_T_ #define _VUID_T_ -typedef u_long vuid_t; -typedef u_long vgid_t; +typedef u_int32_t vuid_t; +typedef u_int32_t vgid_t; #endif /*_VUID_T_ */ #ifndef _CODACRED_T_ #define _CODACRED_T_ struct coda_cred { vuid_t cr_uid, cr_euid, cr_suid, cr_fsuid; /* Real, efftve, set, fs uid*/ -#if defined(__NetBSD__) || defined(__FreeBSD__) - vgid_t cr_groupid, cr_egid, cr_sgid, cr_fsgid; /* same for groups */ -#else - vgid_t cr_gid, cr_egid, cr_sgid, cr_fsgid; /* same for groups */ -#endif + vgid_t cr_groupid, cr_egid, cr_sgid, cr_fsgid; /* same for groups */ }; #endif #ifndef _VENUS_VATTR_T_ #define _VENUS_VATTR_T_ /* * Vnode types. VNON means no type. */ enum coda_vtype { C_VNON, C_VREG, C_VDIR, C_VBLK, C_VCHR, C_VLNK, C_VSOCK, C_VFIFO, C_VBAD }; struct coda_vattr { - enum coda_vtype va_type; /* vnode type (for create) */ + int va_type; /* vnode type (for create) */ u_short va_mode; /* files access mode and type */ short va_nlink; /* number of references to file */ vuid_t va_uid; /* owner user id */ vgid_t va_gid; /* owner group id */ long va_fileid; /* file id */ u_quad_t va_size; /* file size in bytes */ long va_blocksize; /* blocksize preferred for i/o */ struct timespec va_atime; /* time of last access */ struct timespec va_mtime; /* time of last modification */ struct timespec va_ctime; /* time file changed */ u_long va_gen; /* generation number of file */ u_long va_flags; /* flags defined for file */ cdev_t va_rdev; /* device special file represents */ u_quad_t va_bytes; /* bytes of disk space held by file */ u_quad_t va_filerev; /* file modification number */ }; #endif /* * Kernel <--> Venus communications. */ -#define CODA_ROOT ((u_long) 2) -#define CODA_SYNC ((u_long) 3) -#define CODA_OPEN ((u_long) 4) -#define CODA_CLOSE ((u_long) 5) -#define CODA_IOCTL ((u_long) 6) -#define CODA_GETATTR ((u_long) 7) -#define CODA_SETATTR ((u_long) 8) -#define CODA_ACCESS ((u_long) 9) -#define CODA_LOOKUP ((u_long) 10) -#define CODA_CREATE ((u_long) 11) -#define CODA_REMOVE ((u_long) 12) -#define CODA_LINK ((u_long) 13) -#define CODA_RENAME ((u_long) 14) -#define CODA_MKDIR ((u_long) 15) -#define CODA_RMDIR ((u_long) 16) -#define CODA_READDIR ((u_long) 17) -#define CODA_SYMLINK ((u_long) 18) -#define CODA_READLINK ((u_long) 19) -#define CODA_FSYNC ((u_long) 20) -#define CODA_INACTIVE ((u_long) 21) -#define CODA_VGET ((u_long) 22) -#define CODA_SIGNAL ((u_long) 23) -#define CODA_REPLACE ((u_long) 24) -#define CODA_FLUSH ((u_long) 25) -#define CODA_PURGEUSER ((u_long) 26) -#define CODA_ZAPFILE ((u_long) 27) -#define CODA_ZAPDIR ((u_long) 28) -#define CODA_ZAPVNODE ((u_long) 29) -#define CODA_PURGEFID ((u_long) 30) -#define CODA_NCALLS 31 +#define CODA_ROOT 2 +#define CODA_SYNC 3 +#define CODA_OPEN 4 +#define CODA_CLOSE 5 +#define CODA_IOCTL 6 +#define CODA_GETATTR 7 +#define CODA_SETATTR 8 +#define CODA_ACCESS 9 +#define CODA_LOOKUP 10 +#define CODA_CREATE 11 +#define CODA_REMOVE 12 +#define CODA_LINK 13 +#define CODA_RENAME 14 +#define CODA_MKDIR 15 +#define CODA_RMDIR 16 +#define CODA_READDIR 17 +#define CODA_SYMLINK 18 +#define CODA_READLINK 19 +#define CODA_FSYNC 20 +#define CODA_INACTIVE 21 +#define CODA_VGET 22 +#define CODA_SIGNAL 23 +#define CODA_REPLACE 24 +#define CODA_FLUSH 25 +#define CODA_PURGEUSER 26 +#define CODA_ZAPFILE 27 +#define CODA_ZAPDIR 28 +#define CODA_PURGEFID 30 +#define CODA_OPEN_BY_PATH 31 +#define CODA_RESOLVE 32 +#define CODA_REINTEGRATE 33 +#define CODA_NCALLS 34 #define DOWNCALL(opcode) (opcode >= CODA_REPLACE && opcode <= CODA_PURGEFID) #define VC_MAXDATASIZE 8192 #define VC_MAXMSGSIZE sizeof(union inputArgs)+sizeof(union outputArgs) +\ VC_MAXDATASIZE /* * Venus <-> Coda RPC arguments */ struct coda_in_hdr { unsigned long opcode; unsigned long unique; /* Keep multiple outstanding msgs distinct */ u_short pid; /* Common to all */ u_short pgid; /* Common to all */ u_short sid; /* Common to all */ struct coda_cred cred; /* Common to all */ }; /* Really important that opcode and unique are 1st two fields! */ struct coda_out_hdr { unsigned long opcode; unsigned long unique; unsigned long result; }; /* coda_root: NO_IN */ struct coda_root_out { struct coda_out_hdr oh; ViceFid VFid; }; struct coda_root_in { struct coda_in_hdr in; }; /* coda_sync: */ /* Nothing needed for coda_sync */ /* coda_open: */ struct coda_open_in { struct coda_in_hdr ih; ViceFid VFid; int flags; }; struct coda_open_out { struct coda_out_hdr oh; cdev_t dev; ino_t inode; }; /* coda_close: */ struct coda_close_in { struct coda_in_hdr ih; ViceFid VFid; int flags; }; struct coda_close_out { struct coda_out_hdr out; }; /* coda_ioctl: */ struct coda_ioctl_in { struct coda_in_hdr ih; ViceFid VFid; int cmd; int len; int rwflag; char *data; /* Place holder for data. */ }; struct coda_ioctl_out { struct coda_out_hdr oh; int len; caddr_t data; /* Place holder for data. */ }; /* coda_getattr: */ struct coda_getattr_in { struct coda_in_hdr ih; ViceFid VFid; }; struct coda_getattr_out { struct coda_out_hdr oh; struct coda_vattr attr; }; /* coda_setattr: NO_OUT */ struct coda_setattr_in { struct coda_in_hdr ih; ViceFid VFid; struct coda_vattr attr; }; struct coda_setattr_out { struct coda_out_hdr out; }; /* coda_access: NO_OUT */ struct coda_access_in { struct coda_in_hdr ih; ViceFid VFid; int flags; }; struct coda_access_out { struct coda_out_hdr out; }; /* coda_lookup: */ struct coda_lookup_in { struct coda_in_hdr ih; ViceFid VFid; int name; /* Place holder for data. */ }; struct coda_lookup_out { struct coda_out_hdr oh; ViceFid VFid; int vtype; }; /* coda_create: */ struct coda_create_in { struct coda_in_hdr ih; ViceFid VFid; struct coda_vattr attr; int excl; int mode; int name; /* Place holder for data. */ }; struct coda_create_out { struct coda_out_hdr oh; ViceFid VFid; struct coda_vattr attr; }; /* coda_remove: NO_OUT */ struct coda_remove_in { struct coda_in_hdr ih; ViceFid VFid; int name; /* Place holder for data. */ }; struct coda_remove_out { struct coda_out_hdr out; }; /* coda_link: NO_OUT */ struct coda_link_in { struct coda_in_hdr ih; ViceFid sourceFid; /* cnode to link *to* */ ViceFid destFid; /* Directory in which to place link */ int tname; /* Place holder for data. */ }; struct coda_link_out { struct coda_out_hdr out; }; /* coda_rename: NO_OUT */ struct coda_rename_in { struct coda_in_hdr ih; ViceFid sourceFid; int srcname; ViceFid destFid; int destname; }; struct coda_rename_out { struct coda_out_hdr out; }; /* coda_mkdir: */ struct coda_mkdir_in { struct coda_in_hdr ih; ViceFid VFid; struct coda_vattr attr; int name; /* Place holder for data. */ }; struct coda_mkdir_out { struct coda_out_hdr oh; ViceFid VFid; struct coda_vattr attr; }; /* coda_rmdir: NO_OUT */ struct coda_rmdir_in { struct coda_in_hdr ih; ViceFid VFid; int name; /* Place holder for data. */ }; struct coda_rmdir_out { struct coda_out_hdr out; }; /* coda_readdir: */ struct coda_readdir_in { struct coda_in_hdr ih; ViceFid VFid; int count; int offset; }; struct coda_readdir_out { struct coda_out_hdr oh; int size; caddr_t data; /* Place holder for data. */ }; /* coda_symlink: NO_OUT */ struct coda_symlink_in { struct coda_in_hdr ih; ViceFid VFid; /* Directory to put symlink in */ int srcname; struct coda_vattr attr; int tname; }; struct coda_symlink_out { struct coda_out_hdr out; }; /* coda_readlink: */ struct coda_readlink_in { struct coda_in_hdr ih; ViceFid VFid; }; struct coda_readlink_out { struct coda_out_hdr oh; int count; caddr_t data; /* Place holder for data. */ }; /* coda_fsync: NO_OUT */ struct coda_fsync_in { struct coda_in_hdr ih; ViceFid VFid; }; struct coda_fsync_out { struct coda_out_hdr out; }; /* coda_inactive: NO_OUT */ struct coda_inactive_in { struct coda_in_hdr ih; ViceFid VFid; }; /* coda_vget: */ struct coda_vget_in { struct coda_in_hdr ih; ViceFid VFid; }; struct coda_vget_out { struct coda_out_hdr oh; ViceFid VFid; int vtype; }; /* CODA_SIGNAL is out-of-band, doesn't need data. */ /* CODA_INVALIDATE is a venus->kernel call */ /* CODA_FLUSH is a venus->kernel call */ /* coda_purgeuser: */ /* CODA_PURGEUSER is a venus->kernel call */ struct coda_purgeuser_out { struct coda_out_hdr oh; struct coda_cred cred; }; /* coda_zapfile: */ /* CODA_ZAPFILE is a venus->kernel call */ struct coda_zapfile_out { struct coda_out_hdr oh; ViceFid CodaFid; }; /* coda_zapdir: */ /* CODA_ZAPDIR is a venus->kernel call */ struct coda_zapdir_out { struct coda_out_hdr oh; ViceFid CodaFid; }; /* coda_zapnode: */ /* CODA_ZAPVNODE is a venus->kernel call */ struct coda_zapvnode_out { struct coda_out_hdr oh; struct coda_cred cred; ViceFid VFid; }; /* coda_purgefid: */ /* CODA_PURGEFID is a venus->kernel call */ struct coda_purgefid_out { struct coda_out_hdr oh; ViceFid CodaFid; }; /* coda_rdwr: */ struct coda_rdwr_in { struct coda_in_hdr ih; ViceFid VFid; int rwflag; int count; int offset; int ioflag; caddr_t data; /* Place holder for data. */ }; struct coda_rdwr_out { struct coda_out_hdr oh; int rwflag; int count; caddr_t data; /* Place holder for data. */ }; /* coda_replace: */ /* CODA_REPLACE is a venus->kernel call */ struct coda_replace_out { /* coda_replace is a venus->kernel call */ struct coda_out_hdr oh; ViceFid NewFid; ViceFid OldFid; }; +/* coda_open_by_path: */ +struct coda_open_by_path_in { + struct coda_in_hdr ih; + ViceFid VFid; + int flags; +}; + +struct coda_open_by_path_out { + struct coda_out_hdr oh; + int path; +}; + /* - * Occasionally, don't cache the fid returned by CODA_LOOKUP. For instance, if - * the fid is inconsistent. This case is handled by setting the top bit of the - * return result parameter. + * Occasionally, we don't cache the fid returned by CODA_LOOKUP. + * For instance, if the fid is inconsistent. + * This case is handled by setting the top bit of the type result parameter. */ #define CODA_NOCACHE 0x80000000 union inputArgs { struct coda_in_hdr ih; /* NB: every struct below begins with an ih */ struct coda_open_in coda_open; struct coda_close_in coda_close; struct coda_ioctl_in coda_ioctl; struct coda_getattr_in coda_getattr; struct coda_setattr_in coda_setattr; struct coda_access_in coda_access; struct coda_lookup_in coda_lookup; struct coda_create_in coda_create; struct coda_remove_in coda_remove; struct coda_link_in coda_link; struct coda_rename_in coda_rename; struct coda_mkdir_in coda_mkdir; struct coda_rmdir_in coda_rmdir; struct coda_readdir_in coda_readdir; struct coda_symlink_in coda_symlink; struct coda_readlink_in coda_readlink; struct coda_fsync_in coda_fsync; struct coda_inactive_in coda_inactive; struct coda_vget_in coda_vget; struct coda_rdwr_in coda_rdwr; + struct coda_open_by_path_in coda_open_by_path; }; union outputArgs { struct coda_out_hdr oh; /* NB: every struct below begins with an oh */ struct coda_root_out coda_root; struct coda_open_out coda_open; struct coda_ioctl_out coda_ioctl; struct coda_getattr_out coda_getattr; struct coda_lookup_out coda_lookup; struct coda_create_out coda_create; struct coda_mkdir_out coda_mkdir; struct coda_readdir_out coda_readdir; struct coda_readlink_out coda_readlink; struct coda_vget_out coda_vget; struct coda_purgeuser_out coda_purgeuser; struct coda_zapfile_out coda_zapfile; struct coda_zapdir_out coda_zapdir; struct coda_zapvnode_out coda_zapvnode; struct coda_purgefid_out coda_purgefid; struct coda_rdwr_out coda_rdwr; struct coda_replace_out coda_replace; + struct coda_open_by_path_out coda_open_by_path; }; union coda_downcalls { /* CODA_INVALIDATE is a venus->kernel call */ /* CODA_FLUSH is a venus->kernel call */ struct coda_purgeuser_out purgeuser; struct coda_zapfile_out zapfile; struct coda_zapdir_out zapdir; struct coda_zapvnode_out zapvnode; struct coda_purgefid_out purgefid; struct coda_replace_out replace; }; /* * Used for identifying usage of "Control" and pioctls */ #define PIOCPARM_MASK 0x0000ffff struct ViceIoctl { caddr_t in, out; /* Data to be transferred in, or out */ short in_size; /* Size of input buffer <= 2K */ short out_size; /* Maximum size of output buffer, <= 2K */ }; struct PioctlData { const char *path; int follow; struct ViceIoctl vi; }; #define CODA_CONTROL ".CONTROL" #define CODA_CONTROLLEN 8 #define CTL_VOL -1 #define CTL_VNO -1 #define CTL_UNI -1 #define CTL_INO -1 #define CTL_FILE "/coda/.CONTROL" #define IS_CTL_FID(fidp) ((fidp)->Volume == CTL_VOL &&\ (fidp)->Vnode == CTL_VNO &&\ (fidp)->Unique == CTL_UNI) #endif Index: head/sys/coda/coda_namecache.c =================================================================== --- head/sys/coda/coda_namecache.c (revision 40705) +++ head/sys/coda/coda_namecache.c (revision 40706) @@ -1,912 +1,915 @@ /* * * Coda: an Experimental Distributed File System * Release 3.1 * * Copyright (c) 1987-1998 Carnegie Mellon University * All Rights Reserved * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation, and * that credit is given to Carnegie Mellon University in all documents * and publicity pertaining to direct or indirect use of this code or its * derivatives. * * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS KNOWN TO HAVE BUGS, * SOME OF WHICH MAY HAVE SERIOUS CONSEQUENCES. CARNEGIE MELLON ALLOWS * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON * DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE OR OF * ANY DERIVATIVE WORK. * * Carnegie Mellon encourages users of this software to return any * improvements or extensions that they make, and to grant Carnegie * Mellon the rights to redistribute these changes without encumbrance. * * @(#) src/sys/coda/coda_namecache.c,v 1.1.1.1 1998/08/29 21:14:52 rvb Exp $ - * $Id: coda_namecache.c,v 1.6 1998/09/25 17:38:31 rvb Exp $ + * $Id: coda_namecache.c,v 1.7 1998/09/28 20:52:58 rvb Exp $ * */ /* * Mach Operating System * Copyright (c) 1990 Carnegie-Mellon University * Copyright (c) 1989 Carnegie-Mellon University * All rights reserved. The CMU software License Agreement specifies * the terms and conditions for use and redistribution. */ /* * This code was written for the Coda file system at Carnegie Mellon University. * Contributers include David Steere, James Kistler, and M. Satyanarayanan. */ /* * HISTORY * $Log: coda_namecache.c,v $ + * Revision 1.7 1998/09/28 20:52:58 rvb + * Cleanup and fix THE bug + * * Revision 1.6 1998/09/25 17:38:31 rvb * Put "stray" printouts under DIAGNOSTIC. Make everything build * with DEBUG on. Add support for lkm. (The macro's don't work * for me; for a good chuckle look at the end of coda_fbsd.c.) * * Revision 1.5 1998/09/13 13:57:59 rvb * Finish conversion of cfs -> coda * * Revision 1.4 1998/09/11 18:50:17 rvb * All the references to cfs, in symbols, structs, and strings * have been changed to coda. (Same for CFS.) * * Revision 1.2 1998/09/02 19:09:53 rvb * Pass2 complete * * Revision 1.1.1.1 1998/08/29 21:14:52 rvb * Very Preliminary Coda * * Revision 1.11 1998/08/28 18:12:16 rvb * Now it also works on FreeBSD -current. This code will be * committed to the FreeBSD -current and NetBSD -current * trees. It will then be tailored to the particular platform * by flushing conditional code. * * Revision 1.10 1998/08/18 17:05:14 rvb * Don't use __RCSID now * * Revision 1.9 1998/08/18 16:31:39 rvb * Sync the code for NetBSD -current; test on 1.3 later * * Revision 1.8 98/01/31 20:53:10 rvb * First version that works on FreeBSD 2.2.5 * * Revision 1.7 98/01/23 11:53:39 rvb * Bring RVB_CODA1_1 to HEAD * * Revision 1.6.2.4 98/01/23 11:21:02 rvb * Sync with 2.2.5 * * Revision 1.6.2.3 97/12/16 12:40:03 rvb * Sync with 1.3 * * Revision 1.6.2.2 97/12/09 16:07:10 rvb * Sync with vfs/include/coda.h * * Revision 1.6.2.1 97/12/06 17:41:18 rvb * Sync with peters coda.h * * Revision 1.6 97/12/05 10:39:13 rvb * Read CHANGES * * Revision 1.5.4.7 97/11/25 08:08:43 rvb * cfs_venus ... done; until cred/vattr change * * Revision 1.5.4.6 97/11/24 15:44:43 rvb * Final cfs_venus.c w/o macros, but one locking bug * * Revision 1.5.4.5 97/11/20 11:46:38 rvb * Capture current cfs_venus * * Revision 1.5.4.4 97/11/18 10:27:13 rvb * cfs_nbsd.c is DEAD!!!; integrated into cfs_vf/vnops.c * cfs_nb_foo and cfs_foo are joined * * Revision 1.5.4.3 97/11/13 22:02:57 rvb * pass2 cfs_NetBSD.h mt * * Revision 1.5.4.2 97/11/12 12:09:35 rvb * reorg pass1 * * Revision 1.5.4.1 97/10/28 23:10:12 rvb * >64Meg; venus can be killed! * * Revision 1.5 97/08/05 11:08:01 lily * Removed cfsnc_replace, replaced it with a coda_find, unhash, and * rehash. This fixes a cnode leak and a bug in which the fid is * not actually replaced. (cfs_namecache.c, cfsnc.h, cfs_subr.c) * * Revision 1.4 96/12/12 22:10:57 bnoble * Fixed the "downcall invokes venus operation" deadlock in all known cases. * There may be more * * Revision 1.3 1996/11/08 18:06:09 bnoble * Minor changes in vnode operation signature, VOP_UPDATE signature, and * some newly defined bits in the include files. * * Revision 1.2 1996/01/02 16:56:50 bnoble * Added support for Coda MiniCache and raw inode calls (final commit) * * Revision 1.1.2.1 1995/12/20 01:57:15 bnoble * Added CODA-specific files * * Revision 3.1.1.1 1995/03/04 19:07:57 bnoble * Branch for NetBSD port revisions * * Revision 3.1 1995/03/04 19:07:56 bnoble * Bump to major revision 3 to prepare for NetBSD port * * Revision 2.3 1994/10/14 09:57:54 dcs * Made changes 'cause sun4s have braindead compilers * * Revision 2.2 94/08/28 19:37:35 luqi * Add a new CODA_REPLACE call to allow venus to replace a ViceFid in the * mini-cache. * * In "cfs.h": * Add CODA_REPLACE decl. * * In "cfs_namecache.c": * Add routine cfsnc_replace. * * In "cfs_subr.c": * Add case-statement to process CODA_REPLACE. * * In "cfsnc.h": * Add decl for CODA_NC_REPLACE. * * * Revision 2.1 94/07/21 16:25:15 satya * Conversion to C++ 3.0; start of Coda Release 2.0 * * Revision 1.2 92/10/27 17:58:21 lily * merge kernel/latest and alpha/src/cfs * * Revision 2.3 92/09/30 14:16:20 mja * call coda_flush instead of calling inode_uncache_try directly * (from dcs). Also... * * Substituted rvb's history blurb so that we agree with Mach 2.5 sources. * [91/02/09 jjk] * * Added contributors blurb. * [90/12/13 jjk] * * Revision 2.2 90/07/05 11:26:30 mrt * Created for the Coda File System. * [90/05/23 dcs] * * Revision 1.3 90/05/31 17:01:24 dcs * Prepare for merge with facilities kernel. * * */ /* * This module contains the routines to implement the CODA name cache. The * purpose of this cache is to reduce the cost of translating pathnames * into Vice FIDs. Each entry in the cache contains the name of the file, * the vnode (FID) of the parent directory, and the cred structure of the * user accessing the file. * * The first time a file is accessed, it is looked up by the local Venus * which first insures that the user has access to the file. In addition * we are guaranteed that Venus will invalidate any name cache entries in * case the user no longer should be able to access the file. For these * reasons we do not need to keep access list information as well as a * cred structure for each entry. * * The table can be accessed through the routines cnc_init(), cnc_enter(), * cnc_lookup(), cnc_rmfidcred(), cnc_rmfid(), cnc_rmcred(), and cnc_purge(). * There are several other routines which aid in the implementation of the * hash table. */ /* * NOTES: rvb@cs * 1. The name cache holds a reference to every vnode in it. Hence files can not be * closed or made inactive until they are released. * 2. coda_nc_name(cp) was added to get a name for a cnode pointer for debugging. * 3. coda_nc_find() has debug code to detect when entries are stored with different * credentials. We don't understand yet, if/how entries are NOT EQ but still * EQUAL * 4. I wonder if this name cache could be replace by the vnode name cache. * The latter has no zapping functions, so probably not. */ #include #include #include #include #include #ifndef insque #include #endif /* insque */ #include #include #include #include #include #ifdef DEBUG #include #endif /* * Declaration of the name cache data structure. */ int coda_nc_use = 1; /* Indicate use of CODA Name Cache */ int coda_nc_size = CODA_NC_CACHESIZE; /* size of the cache */ int coda_nc_hashsize = CODA_NC_HASHSIZE; /* size of the primary hash */ struct coda_cache *coda_nc_heap; /* pointer to the cache entries */ struct coda_hash *coda_nc_hash; /* hash table of coda_cache pointers */ struct coda_lru coda_nc_lru; /* head of lru chain */ struct coda_nc_statistics coda_nc_stat; /* Keep various stats */ /* * for testing purposes */ int coda_nc_debug = 0; /* * Entry points for the CODA Name Cache */ static struct coda_cache *coda_nc_find(struct cnode *dcp, const char *name, int namelen, struct ucred *cred, int hash); static void coda_nc_remove(struct coda_cache *cncp, enum dc_status dcstat); /* * Initialize the cache, the LRU structure and the Hash structure(s) */ #define TOTAL_CACHE_SIZE (sizeof(struct coda_cache) * coda_nc_size) #define TOTAL_HASH_SIZE (sizeof(struct coda_hash) * coda_nc_hashsize) int coda_nc_initialized = 0; /* Initially the cache has not been initialized */ void coda_nc_init(void) { int i; /* zero the statistics structure */ bzero(&coda_nc_stat, (sizeof(struct coda_nc_statistics))); #ifdef CODA_VERBOSE printf("CODA NAME CACHE: CACHE %d, HASH TBL %d\n", CODA_NC_CACHESIZE, CODA_NC_HASHSIZE); #endif CODA_ALLOC(coda_nc_heap, struct coda_cache *, TOTAL_CACHE_SIZE); CODA_ALLOC(coda_nc_hash, struct coda_hash *, TOTAL_HASH_SIZE); coda_nc_lru.lru_next = coda_nc_lru.lru_prev = (struct coda_cache *)LRU_PART(&coda_nc_lru); for (i=0; i < coda_nc_size; i++) { /* initialize the heap */ CODA_NC_LRUINS(&coda_nc_heap[i], &coda_nc_lru); CODA_NC_HSHNUL(&coda_nc_heap[i]); coda_nc_heap[i].cp = coda_nc_heap[i].dcp = (struct cnode *)0; } for (i=0; i < coda_nc_hashsize; i++) { /* initialize the hashtable */ CODA_NC_HSHNUL((struct coda_cache *)&coda_nc_hash[i]); } coda_nc_initialized++; } /* * Auxillary routines -- shouldn't be entry points */ static struct coda_cache * coda_nc_find(dcp, name, namelen, cred, hash) struct cnode *dcp; const char *name; int namelen; struct ucred *cred; int hash; { /* * hash to find the appropriate bucket, look through the chain * for the right entry (especially right cred, unless cred == 0) */ struct coda_cache *cncp; int count = 1; CODA_NC_DEBUG(CODA_NC_FIND, myprintf(("coda_nc_find(dcp %p, name %s, len %d, cred %p, hash %d\n", dcp, name, namelen, cred, hash));) for (cncp = coda_nc_hash[hash].hash_next; cncp != (struct coda_cache *)&coda_nc_hash[hash]; cncp = cncp->hash_next, count++) { if ((CODA_NAMEMATCH(cncp, name, namelen, dcp)) && ((cred == 0) || (cncp->cred == cred))) { /* compare cr_uid instead */ coda_nc_stat.Search_len += count; return(cncp); } #ifdef DEBUG else if (CODA_NAMEMATCH(cncp, name, namelen, dcp)) { printf("coda_nc_find: name %s, new cred = %p, cred = %p\n", name, cred, cncp->cred); printf("nref %d, nuid %d, ngid %d // oref %d, ocred %d, ogid %d\n", cred->cr_ref, cred->cr_uid, cred->cr_gid, cncp->cred->cr_ref, cncp->cred->cr_uid, cncp->cred->cr_gid); print_cred(cred); print_cred(cncp->cred); } #endif } return((struct coda_cache *)0); } /* * Enter a new (dir cnode, name) pair into the cache, updating the * LRU and Hash as needed. */ void coda_nc_enter(dcp, name, namelen, cred, cp) struct cnode *dcp; const char *name; int namelen; struct ucred *cred; struct cnode *cp; { struct coda_cache *cncp; int hash; if (coda_nc_use == 0) /* Cache is off */ return; CODA_NC_DEBUG(CODA_NC_ENTER, myprintf(("Enter: dcp %p cp %p name %s cred %p \n", dcp, cp, name, cred)); ) if (namelen > CODA_NC_NAMELEN) { CODA_NC_DEBUG(CODA_NC_ENTER, myprintf(("long name enter %s\n",name));) coda_nc_stat.long_name_enters++; /* record stats */ return; } hash = CODA_NC_HASH(name, namelen, dcp); cncp = coda_nc_find(dcp, name, namelen, cred, hash); if (cncp != (struct coda_cache *) 0) { coda_nc_stat.dbl_enters++; /* duplicate entry */ return; } coda_nc_stat.enters++; /* record the enters statistic */ /* Grab the next element in the lru chain */ cncp = CODA_NC_LRUGET(coda_nc_lru); CODA_NC_LRUREM(cncp); /* remove it from the lists */ if (CODA_NC_VALID(cncp)) { /* Seems really ugly, but we have to decrement the appropriate hash bucket length here, so we have to find the hash bucket */ coda_nc_hash[CODA_NC_HASH(cncp->name, cncp->namelen, cncp->dcp)].length--; coda_nc_stat.lru_rm++; /* zapped a valid entry */ CODA_NC_HSHREM(cncp); vrele(CTOV(cncp->dcp)); vrele(CTOV(cncp->cp)); crfree(cncp->cred); } /* * Put a hold on the current vnodes and fill in the cache entry. */ vref(CTOV(cp)); vref(CTOV(dcp)); crhold(cred); cncp->dcp = dcp; cncp->cp = cp; cncp->namelen = namelen; cncp->cred = cred; bcopy(name, cncp->name, (unsigned)namelen); /* Insert into the lru and hash chains. */ CODA_NC_LRUINS(cncp, &coda_nc_lru); CODA_NC_HSHINS(cncp, &coda_nc_hash[hash]); coda_nc_hash[hash].length++; /* Used for tuning */ CODA_NC_DEBUG(CODA_NC_PRINTCODA_NC, print_coda_nc(); ) } /* * Find the (dir cnode, name) pair in the cache, if it's cred * matches the input, return it, otherwise return 0 */ struct cnode * coda_nc_lookup(dcp, name, namelen, cred) struct cnode *dcp; const char *name; int namelen; struct ucred *cred; { int hash; struct coda_cache *cncp; if (coda_nc_use == 0) /* Cache is off */ return((struct cnode *) 0); if (namelen > CODA_NC_NAMELEN) { CODA_NC_DEBUG(CODA_NC_LOOKUP, myprintf(("long name lookup %s\n",name));) coda_nc_stat.long_name_lookups++; /* record stats */ return((struct cnode *) 0); } /* Use the hash function to locate the starting point, then the search routine to go down the list looking for the correct cred. */ hash = CODA_NC_HASH(name, namelen, dcp); cncp = coda_nc_find(dcp, name, namelen, cred, hash); if (cncp == (struct coda_cache *) 0) { coda_nc_stat.misses++; /* record miss */ return((struct cnode *) 0); } coda_nc_stat.hits++; /* put this entry at the end of the LRU */ CODA_NC_LRUREM(cncp); CODA_NC_LRUINS(cncp, &coda_nc_lru); /* move it to the front of the hash chain */ /* don't need to change the hash bucket length */ CODA_NC_HSHREM(cncp); CODA_NC_HSHINS(cncp, &coda_nc_hash[hash]); CODA_NC_DEBUG(CODA_NC_LOOKUP, printf("lookup: dcp %p, name %s, cred %p = cp %p\n", dcp, name, cred, cncp->cp); ) return(cncp->cp); } static void coda_nc_remove(cncp, dcstat) struct coda_cache *cncp; enum dc_status dcstat; { /* * remove an entry -- vrele(cncp->dcp, cp), crfree(cred), * remove it from it's hash chain, and * place it at the head of the lru list. */ CODA_NC_DEBUG(CODA_NC_REMOVE, myprintf(("coda_nc_remove %s from parent %lx.%lx.%lx\n", cncp->name, (cncp->dcp)->c_fid.Volume, (cncp->dcp)->c_fid.Vnode, (cncp->dcp)->c_fid.Unique));) CODA_NC_HSHREM(cncp); CODA_NC_HSHNUL(cncp); /* have it be a null chain */ if ((dcstat == IS_DOWNCALL) && (CTOV(cncp->dcp)->v_usecount == 1)) { cncp->dcp->c_flags |= C_PURGING; } vrele(CTOV(cncp->dcp)); if ((dcstat == IS_DOWNCALL) && (CTOV(cncp->cp)->v_usecount == 1)) { cncp->cp->c_flags |= C_PURGING; } vrele(CTOV(cncp->cp)); crfree(cncp->cred); bzero(DATA_PART(cncp),DATA_SIZE); /* Put the null entry just after the least-recently-used entry */ /* LRU_TOP adjusts the pointer to point to the top of the structure. */ CODA_NC_LRUREM(cncp); CODA_NC_LRUINS(cncp, LRU_TOP(coda_nc_lru.lru_prev)); } /* * Remove all entries with a parent which has the input fid. */ void coda_nc_zapParentfid(fid, dcstat) ViceFid *fid; enum dc_status dcstat; { /* To get to a specific fid, we might either have another hashing function or do a sequential search through the cache for the appropriate entries. The later may be acceptable since I don't think callbacks or whatever Case 1 covers are frequent occurences. */ struct coda_cache *cncp, *ncncp; int i; if (coda_nc_use == 0) /* Cache is off */ return; CODA_NC_DEBUG(CODA_NC_ZAPPFID, myprintf(("ZapParent: fid 0x%lx, 0x%lx, 0x%lx \n", fid->Volume, fid->Vnode, fid->Unique)); ) coda_nc_stat.zapPfids++; for (i = 0; i < coda_nc_hashsize; i++) { /* * Need to save the hash_next pointer in case we remove the * entry. remove causes hash_next to point to itself. */ for (cncp = coda_nc_hash[i].hash_next; cncp != (struct coda_cache *)&coda_nc_hash[i]; cncp = ncncp) { ncncp = cncp->hash_next; if ((cncp->dcp->c_fid.Volume == fid->Volume) && (cncp->dcp->c_fid.Vnode == fid->Vnode) && (cncp->dcp->c_fid.Unique == fid->Unique)) { coda_nc_hash[i].length--; /* Used for tuning */ coda_nc_remove(cncp, dcstat); } } } } /* * Remove all entries which have the same fid as the input */ void coda_nc_zapfid(fid, dcstat) ViceFid *fid; enum dc_status dcstat; { /* See comment for zapParentfid. This routine will be used if attributes are being cached. */ struct coda_cache *cncp, *ncncp; int i; if (coda_nc_use == 0) /* Cache is off */ return; CODA_NC_DEBUG(CODA_NC_ZAPFID, myprintf(("Zapfid: fid 0x%lx, 0x%lx, 0x%lx \n", fid->Volume, fid->Vnode, fid->Unique)); ) coda_nc_stat.zapFids++; for (i = 0; i < coda_nc_hashsize; i++) { for (cncp = coda_nc_hash[i].hash_next; cncp != (struct coda_cache *)&coda_nc_hash[i]; cncp = ncncp) { ncncp = cncp->hash_next; if ((cncp->cp->c_fid.Volume == fid->Volume) && (cncp->cp->c_fid.Vnode == fid->Vnode) && (cncp->cp->c_fid.Unique == fid->Unique)) { coda_nc_hash[i].length--; /* Used for tuning */ coda_nc_remove(cncp, dcstat); } } } } /* * Remove all entries which match the fid and the cred */ void coda_nc_zapvnode(fid, cred, dcstat) ViceFid *fid; struct ucred *cred; enum dc_status dcstat; { /* See comment for zapfid. I don't think that one would ever want to zap a file with a specific cred from the kernel. We'll leave this one unimplemented. */ if (coda_nc_use == 0) /* Cache is off */ return; CODA_NC_DEBUG(CODA_NC_ZAPVNODE, myprintf(("Zapvnode: fid 0x%lx, 0x%lx, 0x%lx cred %p\n", fid->Volume, fid->Vnode, fid->Unique, cred)); ) } /* * Remove all entries which have the (dir vnode, name) pair */ void coda_nc_zapfile(dcp, name, namelen) struct cnode *dcp; const char *name; int namelen; { /* use the hash function to locate the file, then zap all entries of it regardless of the cred. */ struct coda_cache *cncp; int hash; if (coda_nc_use == 0) /* Cache is off */ return; CODA_NC_DEBUG(CODA_NC_ZAPFILE, myprintf(("Zapfile: dcp %p name %s \n", dcp, name)); ) if (namelen > CODA_NC_NAMELEN) { coda_nc_stat.long_remove++; /* record stats */ return; } coda_nc_stat.zapFile++; hash = CODA_NC_HASH(name, namelen, dcp); cncp = coda_nc_find(dcp, name, namelen, 0, hash); while (cncp) { coda_nc_hash[hash].length--; /* Used for tuning */ coda_nc_remove(cncp, NOT_DOWNCALL); cncp = coda_nc_find(dcp, name, namelen, 0, hash); } } /* * Remove all the entries for a particular user. Used when tokens expire. * A user is determined by his/her effective user id (id_uid). */ void coda_nc_purge_user(uid, dcstat) vuid_t uid; enum dc_status dcstat; { /* * I think the best approach is to go through the entire cache * via HASH or whatever and zap all entries which match the * input cred. Or just flush the whole cache. It might be * best to go through on basis of LRU since cache will almost * always be full and LRU is more straightforward. */ struct coda_cache *cncp, *ncncp; int hash; if (coda_nc_use == 0) /* Cache is off */ return; CODA_NC_DEBUG(CODA_NC_PURGEUSER, - myprintf(("ZapDude: uid %lx\n", uid)); ) + myprintf(("ZapDude: uid %x\n", uid)); ) coda_nc_stat.zapUsers++; for (cncp = CODA_NC_LRUGET(coda_nc_lru); cncp != (struct coda_cache *)(&coda_nc_lru); cncp = ncncp) { ncncp = CODA_NC_LRUGET(*cncp); if ((CODA_NC_VALID(cncp)) && ((cncp->cred)->cr_uid == uid)) { /* Seems really ugly, but we have to decrement the appropriate hash bucket length here, so we have to find the hash bucket */ hash = CODA_NC_HASH(cncp->name, cncp->namelen, cncp->dcp); coda_nc_hash[hash].length--; /* For performance tuning */ coda_nc_remove(cncp, dcstat); } } } /* * Flush the entire name cache. In response to a flush of the Venus cache. */ void coda_nc_flush(dcstat) enum dc_status dcstat; { /* One option is to deallocate the current name cache and call init to start again. Or just deallocate, then rebuild. Or again, we could just go through the array and zero the appropriate fields. */ /* * Go through the whole lru chain and kill everything as we go. * I don't use remove since that would rebuild the lru chain * as it went and that seemed unneccesary. */ struct coda_cache *cncp; int i; if (coda_nc_use == 0) /* Cache is off */ return; coda_nc_stat.Flushes++; for (cncp = CODA_NC_LRUGET(coda_nc_lru); cncp != (struct coda_cache *)&coda_nc_lru; cncp = CODA_NC_LRUGET(*cncp)) { if (CODA_NC_VALID(cncp)) { CODA_NC_HSHREM(cncp); /* only zero valid nodes */ CODA_NC_HSHNUL(cncp); if ((dcstat == IS_DOWNCALL) && (CTOV(cncp->dcp)->v_usecount == 1)) { cncp->dcp->c_flags |= C_PURGING; } vrele(CTOV(cncp->dcp)); if (CTOV(cncp->cp)->v_flag & VTEXT) { if (coda_vmflush(cncp->cp)) CODADEBUG(CODA_FLUSH, myprintf(("coda_nc_flush: (%lx.%lx.%lx) busy\n", cncp->cp->c_fid.Volume, cncp->cp->c_fid.Vnode, cncp->cp->c_fid.Unique)); ) } if ((dcstat == IS_DOWNCALL) && (CTOV(cncp->cp)->v_usecount == 1)) { cncp->cp->c_flags |= C_PURGING; } vrele(CTOV(cncp->cp)); crfree(cncp->cred); bzero(DATA_PART(cncp),DATA_SIZE); } } for (i = 0; i < coda_nc_hashsize; i++) coda_nc_hash[i].length = 0; } /* * Debugging routines */ /* * This routine should print out all the hash chains to the console. */ void print_coda_nc(void) { int hash; struct coda_cache *cncp; for (hash = 0; hash < coda_nc_hashsize; hash++) { myprintf(("\nhash %d\n",hash)); for (cncp = coda_nc_hash[hash].hash_next; cncp != (struct coda_cache *)&coda_nc_hash[hash]; cncp = cncp->hash_next) { myprintf(("cp %p dcp %p cred %p name %s\n", cncp->cp, cncp->dcp, cncp->cred, cncp->name)); } } } void coda_nc_gather_stats(void) { int i, max = 0, sum = 0, temp, zeros = 0, ave, n; for (i = 0; i < coda_nc_hashsize; i++) { if (coda_nc_hash[i].length) { sum += coda_nc_hash[i].length; } else { zeros++; } if (coda_nc_hash[i].length > max) max = coda_nc_hash[i].length; } /* * When computing the Arithmetic mean, only count slots which * are not empty in the distribution. */ coda_nc_stat.Sum_bucket_len = sum; coda_nc_stat.Num_zero_len = zeros; coda_nc_stat.Max_bucket_len = max; if ((n = coda_nc_hashsize - zeros) > 0) ave = sum / n; else ave = 0; sum = 0; for (i = 0; i < coda_nc_hashsize; i++) { if (coda_nc_hash[i].length) { temp = coda_nc_hash[i].length - ave; sum += temp * temp; } } coda_nc_stat.Sum2_bucket_len = sum; } /* * The purpose of this routine is to allow the hash and cache sizes to be * changed dynamically. This should only be used in controlled environments, * it makes no effort to lock other users from accessing the cache while it * is in an improper state (except by turning the cache off). */ int coda_nc_resize(hashsize, heapsize, dcstat) int hashsize, heapsize; enum dc_status dcstat; { if ((hashsize % 2) || (heapsize % 2)) { /* Illegal hash or cache sizes */ return(EINVAL); } coda_nc_use = 0; /* Turn the cache off */ coda_nc_flush(dcstat); /* free any cnodes in the cache */ /* WARNING: free must happen *before* size is reset */ CODA_FREE(coda_nc_heap,TOTAL_CACHE_SIZE); CODA_FREE(coda_nc_hash,TOTAL_HASH_SIZE); coda_nc_hashsize = hashsize; coda_nc_size = heapsize; coda_nc_init(); /* Set up a cache with the new size */ coda_nc_use = 1; /* Turn the cache back on */ return(0); } #ifdef DEBUG char coda_nc_name_buf[CODA_MAXNAMLEN+1]; void coda_nc_name(struct cnode *cp) { struct coda_cache *cncp, *ncncp; int i; if (coda_nc_use == 0) /* Cache is off */ return; for (i = 0; i < coda_nc_hashsize; i++) { for (cncp = coda_nc_hash[i].hash_next; cncp != (struct coda_cache *)&coda_nc_hash[i]; cncp = ncncp) { ncncp = cncp->hash_next; if (cncp->cp == cp) { bcopy(cncp->name, coda_nc_name_buf, cncp->namelen); coda_nc_name_buf[cncp->namelen] = 0; printf(" is %s (%p,%p)@%p", coda_nc_name_buf, cncp->cp, cncp->dcp, cncp); } } } } #endif Index: head/sys/coda/coda_subr.c =================================================================== --- head/sys/coda/coda_subr.c (revision 40705) +++ head/sys/coda/coda_subr.c (revision 40706) @@ -1,756 +1,745 @@ /* * * Coda: an Experimental Distributed File System * Release 3.1 * * Copyright (c) 1987-1998 Carnegie Mellon University * All Rights Reserved * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation, and * that credit is given to Carnegie Mellon University in all documents * and publicity pertaining to direct or indirect use of this code or its * derivatives. * * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS KNOWN TO HAVE BUGS, * SOME OF WHICH MAY HAVE SERIOUS CONSEQUENCES. CARNEGIE MELLON ALLOWS * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON * DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE OR OF * ANY DERIVATIVE WORK. * * Carnegie Mellon encourages users of this software to return any * improvements or extensions that they make, and to grant Carnegie * Mellon the rights to redistribute these changes without encumbrance. * * @(#) src/sys/coda/coda_subr.c,v 1.1.1.1 1998/08/29 21:14:52 rvb Exp $ - * $Id: coda_subr.c,v 1.6 1998/09/25 17:38:31 rvb Exp $ + * $Id: coda_subr.c,v 1.7 1998/09/29 20:19:45 rvb Exp $ * */ /* * Mach Operating System * Copyright (c) 1989 Carnegie-Mellon University * All rights reserved. The CMU software License Agreement specifies * the terms and conditions for use and redistribution. */ /* * This code was written for the Coda file system at Carnegie Mellon * University. Contributers include David Steere, James Kistler, and * M. Satyanarayanan. */ /* * HISTORY * $Log: coda_subr.c,v $ + * Revision 1.7 1998/09/29 20:19:45 rvb + * Fixes for lkm: + * 1. use VFS_LKM vs ACTUALLY_LKM_NOT_KERNEL + * 2. don't pass -DCODA to lkm build + * * Revision 1.6 1998/09/25 17:38:31 rvb * Put "stray" printouts under DIAGNOSTIC. Make everything build * with DEBUG on. Add support for lkm. (The macro's don't work * for me; for a good chuckle look at the end of coda_fbsd.c.) * * Revision 1.5 1998/09/13 13:57:59 rvb * Finish conversion of cfs -> coda * * Revision 1.4 1998/09/11 18:50:17 rvb * All the references to cfs, in symbols, structs, and strings * have been changed to coda. (Same for CFS.) * * Revision 1.2 1998/09/02 19:09:53 rvb * Pass2 complete * * Revision 1.1.1.1 1998/08/29 21:14:52 rvb * Very Preliminary Coda * * Revision 1.11 1998/08/28 18:12:18 rvb * Now it also works on FreeBSD -current. This code will be * committed to the FreeBSD -current and NetBSD -current * trees. It will then be tailored to the particular platform * by flushing conditional code. * * Revision 1.10 1998/08/18 17:05:16 rvb * Don't use __RCSID now * * Revision 1.9 1998/08/18 16:31:41 rvb * Sync the code for NetBSD -current; test on 1.3 later * * Revision 1.8 98/01/31 20:53:12 rvb * First version that works on FreeBSD 2.2.5 * * Revision 1.7 98/01/23 11:53:42 rvb * Bring RVB_CODA1_1 to HEAD * * Revision 1.6.2.3 98/01/23 11:21:05 rvb * Sync with 2.2.5 * * Revision 1.6.2.2 97/12/16 12:40:06 rvb * Sync with 1.3 * * Revision 1.6.2.1 97/12/06 17:41:21 rvb * Sync with peters coda.h * * Revision 1.6 97/12/05 10:39:17 rvb * Read CHANGES * * Revision 1.5.4.8 97/11/26 15:28:58 rvb * Cant make downcall pbuf == union cfs_downcalls yet * * Revision 1.5.4.7 97/11/20 11:46:42 rvb * Capture current cfs_venus * * Revision 1.5.4.6 97/11/18 10:27:16 rvb * cfs_nbsd.c is DEAD!!!; integrated into cfs_vf/vnops.c * cfs_nb_foo and cfs_foo are joined * * Revision 1.5.4.5 97/11/13 22:03:00 rvb * pass2 cfs_NetBSD.h mt * * Revision 1.5.4.4 97/11/12 12:09:39 rvb * reorg pass1 * * Revision 1.5.4.3 97/11/06 21:02:38 rvb * first pass at ^c ^z * * Revision 1.5.4.2 97/10/29 16:06:27 rvb * Kill DYING * * Revision 1.5.4.1 97/10/28 23:10:16 rvb * >64Meg; venus can be killed! * * Revision 1.5 97/08/05 11:08:17 lily * Removed cfsnc_replace, replaced it with a coda_find, unhash, and * rehash. This fixes a cnode leak and a bug in which the fid is * not actually replaced. (cfs_namecache.c, cfsnc.h, cfs_subr.c) * * Revision 1.4 96/12/12 22:10:59 bnoble * Fixed the "downcall invokes venus operation" deadlock in all known cases. * There may be more * * Revision 1.3 1996/12/05 16:20:15 bnoble * Minor debugging aids * * Revision 1.2 1996/01/02 16:57:01 bnoble * Added support for Coda MiniCache and raw inode calls (final commit) * * Revision 1.1.2.1 1995/12/20 01:57:27 bnoble * Added CODA-specific files * * Revision 3.1.1.1 1995/03/04 19:07:59 bnoble * Branch for NetBSD port revisions * * Revision 3.1 1995/03/04 19:07:58 bnoble * Bump to major revision 3 to prepare for NetBSD port * * Revision 2.8 1995/03/03 17:00:04 dcs * Fixed kernel bug involving sleep and upcalls. Basically if you killed * a job waiting on venus, the venus upcall queues got trashed. Depending * on luck, you could kill the kernel or not. * (mods to cfs_subr.c and cfs_mach.d) * * Revision 2.7 95/03/02 22:45:21 dcs * Sun4 compatibility * * Revision 2.6 95/02/17 16:25:17 dcs * These versions represent several changes: * 1. Allow venus to restart even if outstanding references exist. * 2. Have only one ctlvp per client, as opposed to one per mounted cfs device.d * 3. Allow ody_expand to return many members, not just one. * * Revision 2.5 94/11/09 15:56:26 dcs * Had the thread sleeping on the wrong thing! * * Revision 2.4 94/10/14 09:57:57 dcs * Made changes 'cause sun4s have braindead compilers * * Revision 2.3 94/10/12 16:46:26 dcs * Cleaned kernel/venus interface by removing XDR junk, plus * so cleanup to allow this code to be more easily ported. * * Revision 1.2 92/10/27 17:58:22 lily * merge kernel/latest and alpha/src/cfs * * Revision 2.4 92/09/30 14:16:26 mja * Incorporated Dave Steere's fix for the GNU-Emacs bug. * Also, included his coda_flush routine in place of the former coda_nc_flush. * [91/02/07 jjk] * * Added contributors blurb. * [90/12/13 jjk] * * Hack to allow users to keep coda venus calls uninterruptible. THis * basically prevents the Gnu-emacs bug from appearing, in which a call * was being interrupted, and return EINTR, but gnu didn't check for the * error and figured the file was buggered. * [90/12/09 dcs] * * Revision 2.3 90/08/10 10:23:20 mrt * Removed include of vm/vm_page.h as it no longer exists. * [90/08/10 mrt] * * Revision 2.2 90/07/05 11:26:35 mrt * Initialize name cache on first call to vcopen. * [90/05/23 dcs] * * Created for the Coda File System. * [90/05/23 dcs] * * Revision 1.5 90/05/31 17:01:35 dcs * Prepare for merge with facilities kernel. * * Revision 1.2 90/03/19 15:56:25 dcs * Initialize name cache on first call to vcopen. * * Revision 1.1 90/03/15 10:43:26 jjk * Initial revision * */ /* NOTES: rvb * 1. Added coda_unmounting to mark all cnodes as being UNMOUNTING. This has to * be done before dounmount is called. Because some of the routines that * dounmount calls before coda_unmounted might try to force flushes to venus. * The vnode pager does this. * 2. coda_unmounting marks all cnodes scanning coda_cache. * 3. cfs_checkunmounting (under DEBUG) checks all cnodes by chasing the vnodes * under the /coda mount point. * 4. coda_cacheprint (under DEBUG) prints names with vnode/cnode address */ #ifdef VFS_LKM #define NVCODA 4 #else #include #endif #include #include #include #include #include #include #include #include #include #include int coda_active = 0; int coda_reuse = 0; int coda_new = 0; struct cnode *coda_freelist = NULL; struct cnode *coda_cache[CODA_CACHESIZE]; #define coda_hash(fid) (((fid)->Volume + (fid)->Vnode) & (CODA_CACHESIZE-1)) #define CNODE_NEXT(cp) ((cp)->c_next) #define ODD(vnode) ((vnode) & 0x1) /* * Allocate a cnode. */ struct cnode * coda_alloc(void) { struct cnode *cp; if (coda_freelist) { cp = coda_freelist; coda_freelist = CNODE_NEXT(cp); coda_reuse++; } else { CODA_ALLOC(cp, struct cnode *, sizeof(struct cnode)); /* NetBSD vnodes don't have any Pager info in them ('cause there are no external pagers, duh!) */ #define VNODE_VM_INFO_INIT(vp) /* MT */ VNODE_VM_INFO_INIT(CTOV(cp)); coda_new++; } bzero(cp, sizeof (struct cnode)); return(cp); } /* * Deallocate a cnode. */ void coda_free(cp) register struct cnode *cp; { CNODE_NEXT(cp) = coda_freelist; coda_freelist = cp; } /* * Put a cnode in the hash table */ void coda_save(cp) struct cnode *cp; { CNODE_NEXT(cp) = coda_cache[coda_hash(&cp->c_fid)]; coda_cache[coda_hash(&cp->c_fid)] = cp; } /* * Remove a cnode from the hash table */ void coda_unsave(cp) struct cnode *cp; { struct cnode *ptr; struct cnode *ptrprev = NULL; ptr = coda_cache[coda_hash(&cp->c_fid)]; while (ptr != NULL) { if (ptr == cp) { if (ptrprev == NULL) { coda_cache[coda_hash(&cp->c_fid)] = CNODE_NEXT(ptr); } else { CNODE_NEXT(ptrprev) = CNODE_NEXT(ptr); } CNODE_NEXT(cp) = (struct cnode *)NULL; return; } ptrprev = ptr; ptr = CNODE_NEXT(ptr); } } /* * Lookup a cnode by fid. If the cnode is dying, it is bogus so skip it. * NOTE: this allows multiple cnodes with same fid -- dcs 1/25/95 */ struct cnode * coda_find(fid) ViceFid *fid; { struct cnode *cp; cp = coda_cache[coda_hash(fid)]; while (cp) { if ((cp->c_fid.Vnode == fid->Vnode) && (cp->c_fid.Volume == fid->Volume) && (cp->c_fid.Unique == fid->Unique) && (!IS_UNMOUNTING(cp))) { coda_active++; return(cp); } cp = CNODE_NEXT(cp); } return(NULL); } /* * coda_kill is called as a side effect to vcopen. To prevent any * cnodes left around from an earlier run of a venus or warden from * causing problems with the new instance, mark any outstanding cnodes * as dying. Future operations on these cnodes should fail (excepting * coda_inactive of course!). Since multiple venii/wardens can be * running, only kill the cnodes for a particular entry in the * coda_mnttbl. -- DCS 12/1/94 */ int coda_kill(whoIam, dcstat) struct mount *whoIam; enum dc_status dcstat; { int hash, count = 0; struct cnode *cp; /* * Algorithm is as follows: * Second, flush whatever vnodes we can from the name cache. * * Finally, step through whatever is left and mark them dying. * This prevents any operation at all. */ /* This is slightly overkill, but should work. Eventually it'd be * nice to only flush those entries from the namecache that * reference a vnode in this vfs. */ coda_nc_flush(dcstat); for (hash = 0; hash < CODA_CACHESIZE; hash++) { for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) { if (CTOV(cp)->v_mount == whoIam) { #ifdef DEBUG printf("coda_kill: vp %p, cp %p\n", CTOV(cp), cp); #endif count++; CODADEBUG(CODA_FLUSH, myprintf(("Live cnode fid %lx.%lx.%lx flags %d count %d\n", (cp->c_fid).Volume, (cp->c_fid).Vnode, (cp->c_fid).Unique, cp->c_flags, CTOV(cp)->v_usecount)); ); } } } return count; } /* * There are two reasons why a cnode may be in use, it may be in the * name cache or it may be executing. */ void coda_flush(dcstat) enum dc_status dcstat; { int hash; struct cnode *cp; coda_clstat.ncalls++; coda_clstat.reqs[CODA_FLUSH]++; coda_nc_flush(dcstat); /* flush files from the name cache */ for (hash = 0; hash < CODA_CACHESIZE; hash++) { for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) { if (!ODD(cp->c_fid.Vnode)) /* only files can be executed */ coda_vmflush(cp); } } } /* * As a debugging measure, print out any cnodes that lived through a * name cache flush. */ void coda_testflush(void) { int hash; struct cnode *cp; for (hash = 0; hash < CODA_CACHESIZE; hash++) { for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) { myprintf(("Live cnode fid %lx.%lx.%lx count %d\n", (cp->c_fid).Volume,(cp->c_fid).Vnode, (cp->c_fid).Unique, CTOV(cp)->v_usecount)); } } } /* * First, step through all cnodes and mark them unmounting. * NetBSD kernels may try to fsync them now that venus * is dead, which would be a bad thing. * */ void coda_unmounting(whoIam) struct mount *whoIam; { int hash; struct cnode *cp; for (hash = 0; hash < CODA_CACHESIZE; hash++) { for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) { if (CTOV(cp)->v_mount == whoIam) { if (cp->c_flags & (C_LOCKED|C_WANTED)) { printf("coda_unmounting: Unlocking %p\n", cp); cp->c_flags &= ~(C_LOCKED|C_WANTED); wakeup((caddr_t) cp); } cp->c_flags |= C_UNMOUNTING; } } } } #ifdef DEBUG void coda_checkunmounting(mp) struct mount *mp; { register struct vnode *vp, *nvp; struct cnode *cp; int count = 0, bad = 0; loop: for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) { if (vp->v_mount != mp) goto loop; nvp = vp->v_mntvnodes.le_next; cp = VTOC(vp); count++; if (!(cp->c_flags & C_UNMOUNTING)) { bad++; printf("vp %p, cp %p missed\n", vp, cp); cp->c_flags |= C_UNMOUNTING; } } } void coda_cacheprint(whoIam) struct mount *whoIam; { int hash; struct cnode *cp; int count = 0; printf("coda_cacheprint: coda_ctlvp %p, cp %p", coda_ctlvp, VTOC(coda_ctlvp)); coda_nc_name(VTOC(coda_ctlvp)); printf("\n"); for (hash = 0; hash < CODA_CACHESIZE; hash++) { for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) { if (CTOV(cp)->v_mount == whoIam) { printf("coda_cacheprint: vp %p, cp %p", CTOV(cp), cp); coda_nc_name(cp); printf("\n"); count++; } } } printf("coda_cacheprint: count %d\n", count); } #endif /* * There are 6 cases where invalidations occur. The semantics of each * is listed here. * * CODA_FLUSH -- flush all entries from the name cache and the cnode cache. * CODA_PURGEUSER -- flush all entries from the name cache for a specific user * This call is a result of token expiration. * * The next two are the result of callbacks on a file or directory. * CODA_ZAPDIR -- flush the attributes for the dir from its cnode. * Zap all children of this directory from the namecache. * CODA_ZAPFILE -- flush the attributes for a file. * * The fifth is a result of Venus detecting an inconsistent file. * CODA_PURGEFID -- flush the attribute for the file * If it is a dir (odd vnode), purge its * children from the namecache * remove the file from the namecache. * * The sixth allows Venus to replace local fids with global ones * during reintegration. * * CODA_REPLACE -- replace one ViceFid with another throughout the name cache */ int handleDownCall(opcode, out) int opcode; union outputArgs *out; { int error; /* Handle invalidate requests. */ switch (opcode) { case CODA_FLUSH : { coda_flush(IS_DOWNCALL); CODADEBUG(CODA_FLUSH,coda_testflush();) /* print remaining cnodes */ return(0); } case CODA_PURGEUSER : { coda_clstat.ncalls++; coda_clstat.reqs[CODA_PURGEUSER]++; /* XXX - need to prevent fsync's */ coda_nc_purge_user(out->coda_purgeuser.cred.cr_uid, IS_DOWNCALL); return(0); } case CODA_ZAPFILE : { struct cnode *cp; error = 0; coda_clstat.ncalls++; coda_clstat.reqs[CODA_ZAPFILE]++; cp = coda_find(&out->coda_zapfile.CodaFid); if (cp != NULL) { vref(CTOV(cp)); cp->c_flags &= ~C_VATTR; if (CTOV(cp)->v_flag & VTEXT) error = coda_vmflush(cp); CODADEBUG(CODA_ZAPFILE, myprintf(("zapfile: fid = (%lx.%lx.%lx), refcnt = %d, error = %d\n", cp->c_fid.Volume, cp->c_fid.Vnode, cp->c_fid.Unique, CTOV(cp)->v_usecount - 1, error));); if (CTOV(cp)->v_usecount == 1) { cp->c_flags |= C_PURGING; } vrele(CTOV(cp)); } return(error); } case CODA_ZAPDIR : { struct cnode *cp; coda_clstat.ncalls++; coda_clstat.reqs[CODA_ZAPDIR]++; cp = coda_find(&out->coda_zapdir.CodaFid); if (cp != NULL) { vref(CTOV(cp)); cp->c_flags &= ~C_VATTR; coda_nc_zapParentfid(&out->coda_zapdir.CodaFid, IS_DOWNCALL); CODADEBUG(CODA_ZAPDIR, myprintf(("zapdir: fid = (%lx.%lx.%lx), refcnt = %d\n",cp->c_fid.Volume, cp->c_fid.Vnode, cp->c_fid.Unique, CTOV(cp)->v_usecount - 1));); if (CTOV(cp)->v_usecount == 1) { cp->c_flags |= C_PURGING; } vrele(CTOV(cp)); } return(0); } - - case CODA_ZAPVNODE : { - coda_clstat.ncalls++; - coda_clstat.reqs[CODA_ZAPVNODE]++; - - myprintf(("CODA_ZAPVNODE: Called, but uniplemented\n")); - /* - * Not that below we must really translate the returned coda_cred to - * a netbsd cred. This is a bit muddled at present and the cfsnc_zapnode - * is further unimplemented, so punt! - * I suppose we could use just the uid. - */ - /* coda_nc_zapvnode(&out->coda_zapvnode.VFid, &out->coda_zapvnode.cred, - IS_DOWNCALL); */ - return(0); - } case CODA_PURGEFID : { struct cnode *cp; error = 0; coda_clstat.ncalls++; coda_clstat.reqs[CODA_PURGEFID]++; cp = coda_find(&out->coda_purgefid.CodaFid); if (cp != NULL) { vref(CTOV(cp)); if (ODD(out->coda_purgefid.CodaFid.Vnode)) { /* Vnode is a directory */ coda_nc_zapParentfid(&out->coda_purgefid.CodaFid, IS_DOWNCALL); } cp->c_flags &= ~C_VATTR; coda_nc_zapfid(&out->coda_purgefid.CodaFid, IS_DOWNCALL); if (!(ODD(out->coda_purgefid.CodaFid.Vnode)) && (CTOV(cp)->v_flag & VTEXT)) { error = coda_vmflush(cp); } CODADEBUG(CODA_PURGEFID, myprintf(("purgefid: fid = (%lx.%lx.%lx), refcnt = %d, error = %d\n", cp->c_fid.Volume, cp->c_fid.Vnode, cp->c_fid.Unique, CTOV(cp)->v_usecount - 1, error));); if (CTOV(cp)->v_usecount == 1) { cp->c_flags |= C_PURGING; } vrele(CTOV(cp)); } return(error); } case CODA_REPLACE : { struct cnode *cp = NULL; coda_clstat.ncalls++; coda_clstat.reqs[CODA_REPLACE]++; cp = coda_find(&out->coda_replace.OldFid); if (cp != NULL) { /* remove the cnode from the hash table, replace the fid, and reinsert */ vref(CTOV(cp)); coda_unsave(cp); cp->c_fid = out->coda_replace.NewFid; coda_save(cp); CODADEBUG(CODA_REPLACE, myprintf(("replace: oldfid = (%lx.%lx.%lx), newfid = (%lx.%lx.%lx), cp = %p\n", out->coda_replace.OldFid.Volume, out->coda_replace.OldFid.Vnode, out->coda_replace.OldFid.Unique, cp->c_fid.Volume, cp->c_fid.Vnode, cp->c_fid.Unique, cp));) vrele(CTOV(cp)); } return (0); } default: myprintf(("handleDownCall: unknown opcode %d\n", opcode)); return (EINVAL); } } /* coda_grab_vnode: lives in either cfs_mach.c or cfs_nbsd.c */ int coda_vmflush(cp) struct cnode *cp; { return 0; } /* * kernel-internal debugging switches */ void coda_debugon(void) { codadebug = -1; coda_nc_debug = -1; coda_vnop_print_entry = 1; coda_psdev_print_entry = 1; coda_vfsop_print_entry = 1; } void coda_debugoff(void) { codadebug = 0; coda_nc_debug = 0; coda_vnop_print_entry = 0; coda_psdev_print_entry = 0; coda_vfsop_print_entry = 0; } /* * Utilities used by both client and server * Standard levels: * 0) no debugging * 1) hard failures * 2) soft failures * 3) current test software * 4) main procedure entry points * 5) main procedure exit points * 6) utility procedure entry points * 7) utility procedure exit points * 8) obscure procedure entry points * 9) obscure procedure exit points * 10) random stuff * 11) all <= 1 * 12) all <= 2 * 13) all <= 3 * ... */ Index: head/sys/coda/coda_venus.c =================================================================== --- head/sys/coda/coda_venus.c (revision 40705) +++ head/sys/coda/coda_venus.c (revision 40706) @@ -1,647 +1,648 @@ /* * * Coda: an Experimental Distributed File System * Release 3.1 * * Copyright (c) 1987-1998 Carnegie Mellon University * All Rights Reserved * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation, and * that credit is given to Carnegie Mellon University in all documents * and publicity pertaining to direct or indirect use of this code or its * derivatives. * * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS KNOWN TO HAVE BUGS, * SOME OF WHICH MAY HAVE SERIOUS CONSEQUENCES. CARNEGIE MELLON ALLOWS * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON * DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE OR OF * ANY DERIVATIVE WORK. * * Carnegie Mellon encourages users of this software to return any * improvements or extensions that they make, and to grant Carnegie * Mellon the rights to redistribute these changes without encumbrance. * * @(#) src/sys/cfs/coda_venus.c,v 1.1.1.1 1998/08/29 21:14:52 rvb Exp $ - * $Id: coda_venus.c,v 1.3 1998/09/11 18:50:17 rvb Exp $ + * $Id: coda_venus.c,v 1.4 1998/09/13 13:57:59 rvb Exp $ * */ #include #include #include #include #include #include #include #include #include #include #include #define DECL_NO_IN(name) \ struct coda_in_hdr *inp; \ struct name ## _out *outp; \ int name ## _size = sizeof (struct coda_in_hdr); \ int Isize = sizeof (struct coda_in_hdr); \ int Osize = sizeof (struct name ## _out); \ int error #define DECL(name) \ struct name ## _in *inp; \ struct name ## _out *outp; \ int name ## _size = sizeof (struct name ## _in); \ int Isize = sizeof (struct name ## _in); \ int Osize = sizeof (struct name ## _out); \ int error #define DECL_NO_OUT(name) \ struct name ## _in *inp; \ struct coda_out_hdr *outp; \ int name ## _size = sizeof (struct name ## _in); \ int Isize = sizeof (struct name ## _in); \ int Osize = sizeof (struct coda_out_hdr); \ int error #define ALLOC_NO_IN(name) \ if (Osize > name ## _size) \ name ## _size = Osize; \ CODA_ALLOC(inp, struct coda_in_hdr *, name ## _size);\ outp = (struct name ## _out *) inp #define ALLOC(name) \ if (Osize > name ## _size) \ name ## _size = Osize; \ CODA_ALLOC(inp, struct name ## _in *, name ## _size);\ outp = (struct name ## _out *) inp #define ALLOC_NO_OUT(name) \ if (Osize > name ## _size) \ name ## _size = Osize; \ CODA_ALLOC(inp, struct name ## _in *, name ## _size);\ outp = (struct coda_out_hdr *) inp #define STRCPY(struc, name, len) \ bcopy(name, (char *)inp + (int)inp->struc, len); \ ((char*)inp + (int)inp->struc)[len++] = 0; \ Isize += len #define INIT_IN(in, op, ident, p) \ (in)->opcode = (op); \ (in)->pid = p ? p->p_pid : -1; \ (in)->pgid = p ? p->p_pgid : -1; \ (in)->sid = (p && p->p_session && p->p_session->s_leader) ? (p->p_session->s_leader->p_pid) : -1; \ if (ident != NOCRED) { \ (in)->cred.cr_uid = ident->cr_uid; \ (in)->cred.cr_groupid = ident->cr_gid; \ } else { \ bzero(&((in)->cred),sizeof(struct coda_cred)); \ (in)->cred.cr_uid = -1; \ (in)->cred.cr_groupid = -1; \ } \ #define CNV_OFLAG(to, from) \ do { \ to = 0; \ if (from & FREAD) to |= C_O_READ; \ if (from & FWRITE) to |= C_O_WRITE; \ if (from & O_TRUNC) to |= C_O_TRUNC; \ if (from & O_EXCL) to |= C_O_EXCL; \ + if (from & O_CREAT) to |= C_O_CREAT; \ } while (0) #define CNV_VV2V_ATTR(top, fromp) \ do { \ (top)->va_type = (fromp)->va_type; \ (top)->va_mode = (fromp)->va_mode; \ (top)->va_nlink = (fromp)->va_nlink; \ (top)->va_uid = (fromp)->va_uid; \ (top)->va_gid = (fromp)->va_gid; \ (top)->va_fsid = VNOVAL; \ (top)->va_fileid = (fromp)->va_fileid; \ (top)->va_size = (fromp)->va_size; \ (top)->va_blocksize = (fromp)->va_blocksize; \ (top)->va_atime = (fromp)->va_atime; \ (top)->va_mtime = (fromp)->va_mtime; \ (top)->va_ctime = (fromp)->va_ctime; \ (top)->va_gen = (fromp)->va_gen; \ (top)->va_flags = (fromp)->va_flags; \ (top)->va_rdev = (fromp)->va_rdev; \ (top)->va_bytes = (fromp)->va_bytes; \ (top)->va_filerev = (fromp)->va_filerev; \ (top)->va_vaflags = VNOVAL; \ (top)->va_spare = VNOVAL; \ } while (0) #define CNV_V2VV_ATTR(top, fromp) \ do { \ (top)->va_type = (fromp)->va_type; \ (top)->va_mode = (fromp)->va_mode; \ (top)->va_nlink = (fromp)->va_nlink; \ (top)->va_uid = (fromp)->va_uid; \ (top)->va_gid = (fromp)->va_gid; \ (top)->va_fileid = (fromp)->va_fileid; \ (top)->va_size = (fromp)->va_size; \ (top)->va_blocksize = (fromp)->va_blocksize; \ (top)->va_atime = (fromp)->va_atime; \ (top)->va_mtime = (fromp)->va_mtime; \ (top)->va_ctime = (fromp)->va_ctime; \ (top)->va_gen = (fromp)->va_gen; \ (top)->va_flags = (fromp)->va_flags; \ (top)->va_rdev = (fromp)->va_rdev; \ (top)->va_bytes = (fromp)->va_bytes; \ (top)->va_filerev = (fromp)->va_filerev; \ } while (0) int venus_root(void *mdp, struct ucred *cred, struct proc *p, /*out*/ ViceFid *VFid) { DECL_NO_IN(coda_root); /* sets Isize & Osize */ ALLOC_NO_IN(coda_root); /* sets inp & outp */ /* send the open to venus. */ INIT_IN(inp, CODA_ROOT, cred, p); error = coda_call(mdp, Isize, &Osize, (char *)inp); if (!error) *VFid = outp->VFid; CODA_FREE(inp, coda_root_size); return error; } int venus_open(void *mdp, ViceFid *fid, int flag, struct ucred *cred, struct proc *p, /*out*/ dev_t *dev, ino_t *inode) { int cflag; DECL(coda_open); /* sets Isize & Osize */ ALLOC(coda_open); /* sets inp & outp */ /* send the open to venus. */ INIT_IN(&inp->ih, CODA_OPEN, cred, p); inp->VFid = *fid; CNV_OFLAG(cflag, flag); inp->flags = cflag; error = coda_call(mdp, Isize, &Osize, (char *)inp); if (!error) { *dev = outp->dev; *inode = outp->inode; } CODA_FREE(inp, coda_open_size); return error; } int venus_close(void *mdp, ViceFid *fid, int flag, struct ucred *cred, struct proc *p) { int cflag; DECL_NO_OUT(coda_close); /* sets Isize & Osize */ ALLOC_NO_OUT(coda_close); /* sets inp & outp */ INIT_IN(&inp->ih, CODA_CLOSE, cred, p); inp->VFid = *fid; CNV_OFLAG(cflag, flag); inp->flags = cflag; error = coda_call(mdp, Isize, &Osize, (char *)inp); CODA_FREE(inp, coda_close_size); return error; } /* * these two calls will not exist!!! the container file is read/written * directly. */ void venus_read(void) { } void venus_write(void) { } /* * this is a bit sad too. the ioctl's are for the control file, not for * normal files. */ int venus_ioctl(void *mdp, ViceFid *fid, int com, int flag, caddr_t data, struct ucred *cred, struct proc *p) { DECL(coda_ioctl); /* sets Isize & Osize */ struct PioctlData *iap = (struct PioctlData *)data; int tmp; coda_ioctl_size = VC_MAXMSGSIZE; ALLOC(coda_ioctl); /* sets inp & outp */ INIT_IN(&inp->ih, CODA_IOCTL, cred, p); inp->VFid = *fid; /* command was mutated by increasing its size field to reflect the * path and follow args. we need to subtract that out before sending * the command to venus. */ inp->cmd = (com & ~(IOCPARM_MASK << 16)); tmp = ((com >> 16) & IOCPARM_MASK) - sizeof (char *) - sizeof (int); inp->cmd |= (tmp & IOCPARM_MASK) << 16; inp->rwflag = flag; inp->len = iap->vi.in_size; inp->data = (char *)(sizeof (struct coda_ioctl_in)); error = copyin(iap->vi.in, (char*)inp + (int)inp->data, iap->vi.in_size); if (error) { CODA_FREE(inp, coda_ioctl_size); return(error); } Osize = VC_MAXMSGSIZE; error = coda_call(mdp, Isize + iap->vi.in_size, &Osize, (char *)inp); /* copy out the out buffer. */ if (!error) { if (outp->len > iap->vi.out_size) { error = EINVAL; } else { error = copyout((char *)outp + (int)outp->data, iap->vi.out, iap->vi.out_size); } } CODA_FREE(inp, coda_ioctl_size); return error; } int venus_getattr(void *mdp, ViceFid *fid, struct ucred *cred, struct proc *p, /*out*/ struct vattr *vap) { DECL(coda_getattr); /* sets Isize & Osize */ ALLOC(coda_getattr); /* sets inp & outp */ /* send the open to venus. */ INIT_IN(&inp->ih, CODA_GETATTR, cred, p); inp->VFid = *fid; error = coda_call(mdp, Isize, &Osize, (char *)inp); if (!error) { CNV_VV2V_ATTR(vap, &outp->attr); } CODA_FREE(inp, coda_getattr_size); return error; } int venus_setattr(void *mdp, ViceFid *fid, struct vattr *vap, struct ucred *cred, struct proc *p) { DECL_NO_OUT(coda_setattr); /* sets Isize & Osize */ ALLOC_NO_OUT(coda_setattr); /* sets inp & outp */ /* send the open to venus. */ INIT_IN(&inp->ih, CODA_SETATTR, cred, p); inp->VFid = *fid; CNV_V2VV_ATTR(&inp->attr, vap); error = coda_call(mdp, Isize, &Osize, (char *)inp); CODA_FREE(inp, coda_setattr_size); return error; } int venus_access(void *mdp, ViceFid *fid, int mode, struct ucred *cred, struct proc *p) { DECL_NO_OUT(coda_access); /* sets Isize & Osize */ ALLOC_NO_OUT(coda_access); /* sets inp & outp */ /* send the open to venus. */ INIT_IN(&inp->ih, CODA_ACCESS, cred, p); inp->VFid = *fid; /* NOTE: * NetBSD and Venus internals use the "data" in the low 3 bits. * Hence, the conversion. */ inp->flags = mode>>6; error = coda_call(mdp, Isize, &Osize, (char *)inp); CODA_FREE(inp, coda_access_size); return error; } int venus_readlink(void *mdp, ViceFid *fid, struct ucred *cred, struct proc *p, /*out*/ char **str, int *len) { DECL(coda_readlink); /* sets Isize & Osize */ coda_readlink_size += CODA_MAXPATHLEN; ALLOC(coda_readlink); /* sets inp & outp */ /* send the open to venus. */ INIT_IN(&inp->ih, CODA_READLINK, cred, p); inp->VFid = *fid; Osize += CODA_MAXPATHLEN; error = coda_call(mdp, Isize, &Osize, (char *)inp); if (!error) { CODA_ALLOC(*str, char *, outp->count); *len = outp->count; bcopy((char *)outp + (int)outp->data, *str, *len); } CODA_FREE(inp, coda_readlink_size); return error; } int venus_fsync(void *mdp, ViceFid *fid, struct ucred *cred, struct proc *p) { DECL_NO_OUT(coda_fsync); /* sets Isize & Osize */ ALLOC_NO_OUT(coda_fsync); /* sets inp & outp */ /* send the open to venus. */ INIT_IN(&inp->ih, CODA_FSYNC, cred, p); inp->VFid = *fid; error = coda_call(mdp, Isize, &Osize, (char *)inp); CODA_FREE(inp, coda_fsync_size); return error; } int venus_lookup(void *mdp, ViceFid *fid, const char *nm, int len, struct ucred *cred, struct proc *p, /*out*/ ViceFid *VFid, int *vtype) { DECL(coda_lookup); /* sets Isize & Osize */ coda_lookup_size += len + 1; ALLOC(coda_lookup); /* sets inp & outp */ /* send the open to venus. */ INIT_IN(&inp->ih, CODA_LOOKUP, cred, p); inp->VFid = *fid; inp->name = Isize; STRCPY(name, nm, len); /* increments Isize */ error = coda_call(mdp, Isize, &Osize, (char *)inp); if (!error) { *VFid = outp->VFid; *vtype = outp->vtype; } CODA_FREE(inp, coda_lookup_size); return error; } int venus_create(void *mdp, ViceFid *fid, const char *nm, int len, int exclusive, int mode, struct vattr *va, struct ucred *cred, struct proc *p, /*out*/ ViceFid *VFid, struct vattr *attr) { DECL(coda_create); /* sets Isize & Osize */ coda_create_size += len + 1; ALLOC(coda_create); /* sets inp & outp */ /* send the open to venus. */ INIT_IN(&inp->ih, CODA_CREATE, cred, p); inp->VFid = *fid; inp->excl = exclusive ? C_O_EXCL : 0; inp->mode = mode; CNV_V2VV_ATTR(&inp->attr, va); inp->name = Isize; STRCPY(name, nm, len); /* increments Isize */ error = coda_call(mdp, Isize, &Osize, (char *)inp); if (!error) { *VFid = outp->VFid; CNV_VV2V_ATTR(attr, &outp->attr); } CODA_FREE(inp, coda_create_size); return error; } int venus_remove(void *mdp, ViceFid *fid, const char *nm, int len, struct ucred *cred, struct proc *p) { DECL_NO_OUT(coda_remove); /* sets Isize & Osize */ coda_remove_size += len + 1; ALLOC_NO_OUT(coda_remove); /* sets inp & outp */ /* send the open to venus. */ INIT_IN(&inp->ih, CODA_REMOVE, cred, p); inp->VFid = *fid; inp->name = Isize; STRCPY(name, nm, len); /* increments Isize */ error = coda_call(mdp, Isize, &Osize, (char *)inp); CODA_FREE(inp, coda_remove_size); return error; } int venus_link(void *mdp, ViceFid *fid, ViceFid *tfid, const char *nm, int len, struct ucred *cred, struct proc *p) { DECL_NO_OUT(coda_link); /* sets Isize & Osize */ coda_link_size += len + 1; ALLOC_NO_OUT(coda_link); /* sets inp & outp */ /* send the open to venus. */ INIT_IN(&inp->ih, CODA_LINK, cred, p); inp->sourceFid = *fid; inp->destFid = *tfid; inp->tname = Isize; STRCPY(tname, nm, len); /* increments Isize */ error = coda_call(mdp, Isize, &Osize, (char *)inp); CODA_FREE(inp, coda_link_size); return error; } int venus_rename(void *mdp, ViceFid *fid, ViceFid *tfid, const char *nm, int len, const char *tnm, int tlen, struct ucred *cred, struct proc *p) { DECL_NO_OUT(coda_rename); /* sets Isize & Osize */ coda_rename_size += len + 1 + tlen + 1; ALLOC_NO_OUT(coda_rename); /* sets inp & outp */ /* send the open to venus. */ INIT_IN(&inp->ih, CODA_RENAME, cred, p); inp->sourceFid = *fid; inp->destFid = *tfid; inp->srcname = Isize; STRCPY(srcname, nm, len); /* increments Isize */ inp->destname = Isize; STRCPY(destname, tnm, tlen); /* increments Isize */ error = coda_call(mdp, Isize, &Osize, (char *)inp); CODA_FREE(inp, coda_rename_size); return error; } int venus_mkdir(void *mdp, ViceFid *fid, const char *nm, int len, struct vattr *va, struct ucred *cred, struct proc *p, /*out*/ ViceFid *VFid, struct vattr *ova) { DECL(coda_mkdir); /* sets Isize & Osize */ coda_mkdir_size += len + 1; ALLOC(coda_mkdir); /* sets inp & outp */ /* send the open to venus. */ INIT_IN(&inp->ih, CODA_MKDIR, cred, p); inp->VFid = *fid; CNV_V2VV_ATTR(&inp->attr, va); inp->name = Isize; STRCPY(name, nm, len); /* increments Isize */ error = coda_call(mdp, Isize, &Osize, (char *)inp); if (!error) { *VFid = outp->VFid; CNV_VV2V_ATTR(ova, &outp->attr); } CODA_FREE(inp, coda_mkdir_size); return error; } int venus_rmdir(void *mdp, ViceFid *fid, const char *nm, int len, struct ucred *cred, struct proc *p) { DECL_NO_OUT(coda_rmdir); /* sets Isize & Osize */ coda_rmdir_size += len + 1; ALLOC_NO_OUT(coda_rmdir); /* sets inp & outp */ /* send the open to venus. */ INIT_IN(&inp->ih, CODA_RMDIR, cred, p); inp->VFid = *fid; inp->name = Isize; STRCPY(name, nm, len); /* increments Isize */ error = coda_call(mdp, Isize, &Osize, (char *)inp); CODA_FREE(inp, coda_rmdir_size); return error; } int venus_symlink(void *mdp, ViceFid *fid, const char *lnm, int llen, const char *nm, int len, struct vattr *va, struct ucred *cred, struct proc *p) { DECL_NO_OUT(coda_symlink); /* sets Isize & Osize */ coda_symlink_size += llen + 1 + len + 1; ALLOC_NO_OUT(coda_symlink); /* sets inp & outp */ /* send the open to venus. */ INIT_IN(&inp->ih, CODA_SYMLINK, cred, p); inp->VFid = *fid; CNV_V2VV_ATTR(&inp->attr, va); inp->srcname = Isize; STRCPY(srcname, lnm, llen); /* increments Isize */ inp->tname = Isize; STRCPY(tname, nm, len); /* increments Isize */ error = coda_call(mdp, Isize, &Osize, (char *)inp); CODA_FREE(inp, coda_symlink_size); return error; } int venus_readdir(void *mdp, ViceFid *fid, int count, int offset, struct ucred *cred, struct proc *p, /*out*/ char *buffer, int *len) { DECL(coda_readdir); /* sets Isize & Osize */ coda_readdir_size = VC_MAXMSGSIZE; ALLOC(coda_readdir); /* sets inp & outp */ /* send the open to venus. */ INIT_IN(&inp->ih, CODA_READDIR, cred, p); inp->VFid = *fid; inp->count = count; inp->offset = offset; Osize = VC_MAXMSGSIZE; error = coda_call(mdp, Isize, &Osize, (char *)inp); if (!error) { bcopy((char *)outp + (int)outp->data, buffer, outp->size); *len = outp->size; } CODA_FREE(inp, coda_readdir_size); return error; } int venus_fhtovp(void *mdp, ViceFid *fid, struct ucred *cred, struct proc *p, /*out*/ ViceFid *VFid, int *vtype) { DECL(coda_vget); /* sets Isize & Osize */ ALLOC(coda_vget); /* sets inp & outp */ /* Send the open to Venus. */ INIT_IN(&inp->ih, CODA_VGET, cred, p); inp->VFid = *fid; error = coda_call(mdp, Isize, &Osize, (char *)inp); if (!error) { *VFid = outp->VFid; *vtype = outp->vtype; } CODA_FREE(inp, coda_vget_size); return error; } Index: head/sys/fs/coda/coda.h =================================================================== --- head/sys/fs/coda/coda.h (revision 40705) +++ head/sys/fs/coda/coda.h (revision 40706) @@ -1,677 +1,733 @@ /* * * Coda: an Experimental Distributed File System * Release 3.1 * * Copyright (c) 1987-1998 Carnegie Mellon University * All Rights Reserved * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation, and * that credit is given to Carnegie Mellon University in all documents * and publicity pertaining to direct or indirect use of this code or its * derivatives. * * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS KNOWN TO HAVE BUGS, * SOME OF WHICH MAY HAVE SERIOUS CONSEQUENCES. CARNEGIE MELLON ALLOWS * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON * DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE OR OF * ANY DERIVATIVE WORK. * * Carnegie Mellon encourages users of this software to return any * improvements or extensions that they make, and to grant Carnegie * Mellon the rights to redistribute these changes without encumbrance. * * @(#) src/sys/coda/coda.h,v 1.1.1.1 1998/08/29 21:14:52 rvb Exp $ - * $Id: coda.h,v 1.3 1998/09/11 18:50:17 rvb Exp $ + * $Id: coda.h,v 1.4 1998/09/13 13:57:59 rvb Exp $ * */ /* * * Based on cfs.h from Mach, but revamped for increased simplicity. * Linux modifications by Peter Braam, Aug 1996 */ #ifndef _CODA_HEADER_ #define _CODA_HEADER_ + + /* Catch new _KERNEL defn for NetBSD */ #ifdef __NetBSD__ #include #endif -#if defined(__linux__) || defined(__CYGWIN32__) +#ifndef CODA_MAXSYMLINKS +#define CODA_MAXSYMLINKS 10 +#endif + +#if defined(DJGPP) || defined(__CYGWIN32__) +#ifdef KERNEL +typedef unsigned long u_long; +typedef unsigned int u_int; +typedef unsigned short u_short; +typedef u_long ino_t; +typedef u_long dev_t; +typedef void * caddr_t; +typedef unsigned long long u_quad_t; + +#define inline + +struct timespec { + long ts_sec; + long ts_nsec; +}; +#else /* DJGPP but not KERNEL */ +#include +#include +typedef unsigned long long u_quad_t; +#endif /* !KERNEL */ +#endif /* !DJGPP */ + + +#if defined(__linux__) #define cdev_t u_quad_t #if !defined(_UQUAD_T_) && (!defined(__GLIBC__) || __GLIBC__ < 2) #define _UQUAD_T_ 1 typedef unsigned long long u_quad_t; -#endif +#endif #else #define cdev_t dev_t #endif #ifdef __CYGWIN32__ typedef unsigned char u_int8_t; struct timespec { time_t tv_sec; /* seconds */ long tv_nsec; /* nanoseconds */ }; #endif /* - * Coda constants + * Cfs constants */ #define CODA_MAXNAMLEN 255 #define CODA_MAXPATHLEN 1024 #define CODA_MAXSYMLINK 10 /* these are Coda's version of O_RDONLY etc combinations * to deal with VFS open modes */ #define C_O_READ 0x001 #define C_O_WRITE 0x002 #define C_O_TRUNC 0x010 #define C_O_EXCL 0x100 +#define C_O_CREAT 0x200 /* these are to find mode bits in Venus */ #define C_M_READ 00400 #define C_M_WRITE 00200 /* for access Venus will use */ +#define C_A_C_OK 8 /* Test for writing upon create. */ #define C_A_R_OK 4 /* Test for read permission. */ #define C_A_W_OK 2 /* Test for write permission. */ #define C_A_X_OK 1 /* Test for execute permission. */ #define C_A_F_OK 0 /* Test for existence. */ #ifndef _VENUS_DIRENT_T_ #define _VENUS_DIRENT_T_ 1 struct venus_dirent { unsigned long d_fileno; /* file number of entry */ unsigned short d_reclen; /* length of this record */ char d_type; /* file type, see below */ char d_namlen; /* length of string in d_name */ char d_name[CODA_MAXNAMLEN + 1];/* name must be no longer than this */ }; #undef DIRSIZ #define DIRSIZ(dp) ((sizeof (struct venus_dirent) - (CODA_MAXNAMLEN+1)) + \ (((dp)->d_namlen+1 + 3) &~ 3)) /* * File types */ #define CDT_UNKNOWN 0 -#define CDT_FIFO 1 +#define CDT_FIFO 1 #define CDT_CHR 2 #define CDT_DIR 4 #define CDT_BLK 6 #define CDT_REG 8 #define CDT_LNK 10 -#define CDT_SOCK 12 +#define CDT_SOCK 12 #define CDT_WHT 14 /* * Convert between stat structure types and directory types. */ #define IFTOCDT(mode) (((mode) & 0170000) >> 12) #define CDTTOIF(dirtype) ((dirtype) << 12) #endif #ifndef _FID_T_ #define _FID_T_ 1 typedef u_long VolumeId; typedef u_long VnodeId; typedef u_long Unique_t; typedef u_long FileVersion; #endif #ifndef _VICEFID_T_ #define _VICEFID_T_ 1 typedef struct ViceFid { VolumeId Volume; VnodeId Vnode; Unique_t Unique; } ViceFid; #endif /* VICEFID */ -#ifdef __linux__ -static inline ino_t coda_f2i(struct ViceFid *fid) + +#ifdef __linux__ +static __inline__ ino_t coda_f2i(struct ViceFid *fid) { - if ( fid ) { - return (fid->Unique + (fid->Vnode << 10) + (fid->Volume << 20)); - } else { - return 0; - } + if ( ! fid ) + return 0; + if (fid->Vnode == 0xfffffffe || fid->Vnode == 0xffffffff) + return ((fid->Volume << 20) | (fid->Unique & 0xfffff)); + else + return (fid->Unique + (fid->Vnode<<10) + (fid->Volume<<20)); } + +#else +#define coda_f2i(fid)\ + (fid) ? ((fid)->Unique + ((fid)->Vnode<<10) + ((fid)->Volume<<20)) : 0 #endif + +#ifndef __BIT_TYPES_DEFINED__ +#define u_int32_t unsigned int +#endif + + #ifndef _VUID_T_ #define _VUID_T_ -typedef u_long vuid_t; -typedef u_long vgid_t; +typedef u_int32_t vuid_t; +typedef u_int32_t vgid_t; #endif /*_VUID_T_ */ #ifndef _CODACRED_T_ #define _CODACRED_T_ struct coda_cred { vuid_t cr_uid, cr_euid, cr_suid, cr_fsuid; /* Real, efftve, set, fs uid*/ -#if defined(__NetBSD__) || defined(__FreeBSD__) - vgid_t cr_groupid, cr_egid, cr_sgid, cr_fsgid; /* same for groups */ -#else - vgid_t cr_gid, cr_egid, cr_sgid, cr_fsgid; /* same for groups */ -#endif + vgid_t cr_groupid, cr_egid, cr_sgid, cr_fsgid; /* same for groups */ }; #endif #ifndef _VENUS_VATTR_T_ #define _VENUS_VATTR_T_ /* * Vnode types. VNON means no type. */ enum coda_vtype { C_VNON, C_VREG, C_VDIR, C_VBLK, C_VCHR, C_VLNK, C_VSOCK, C_VFIFO, C_VBAD }; struct coda_vattr { - enum coda_vtype va_type; /* vnode type (for create) */ + int va_type; /* vnode type (for create) */ u_short va_mode; /* files access mode and type */ short va_nlink; /* number of references to file */ vuid_t va_uid; /* owner user id */ vgid_t va_gid; /* owner group id */ long va_fileid; /* file id */ u_quad_t va_size; /* file size in bytes */ long va_blocksize; /* blocksize preferred for i/o */ struct timespec va_atime; /* time of last access */ struct timespec va_mtime; /* time of last modification */ struct timespec va_ctime; /* time file changed */ u_long va_gen; /* generation number of file */ u_long va_flags; /* flags defined for file */ cdev_t va_rdev; /* device special file represents */ u_quad_t va_bytes; /* bytes of disk space held by file */ u_quad_t va_filerev; /* file modification number */ }; #endif /* * Kernel <--> Venus communications. */ -#define CODA_ROOT ((u_long) 2) -#define CODA_SYNC ((u_long) 3) -#define CODA_OPEN ((u_long) 4) -#define CODA_CLOSE ((u_long) 5) -#define CODA_IOCTL ((u_long) 6) -#define CODA_GETATTR ((u_long) 7) -#define CODA_SETATTR ((u_long) 8) -#define CODA_ACCESS ((u_long) 9) -#define CODA_LOOKUP ((u_long) 10) -#define CODA_CREATE ((u_long) 11) -#define CODA_REMOVE ((u_long) 12) -#define CODA_LINK ((u_long) 13) -#define CODA_RENAME ((u_long) 14) -#define CODA_MKDIR ((u_long) 15) -#define CODA_RMDIR ((u_long) 16) -#define CODA_READDIR ((u_long) 17) -#define CODA_SYMLINK ((u_long) 18) -#define CODA_READLINK ((u_long) 19) -#define CODA_FSYNC ((u_long) 20) -#define CODA_INACTIVE ((u_long) 21) -#define CODA_VGET ((u_long) 22) -#define CODA_SIGNAL ((u_long) 23) -#define CODA_REPLACE ((u_long) 24) -#define CODA_FLUSH ((u_long) 25) -#define CODA_PURGEUSER ((u_long) 26) -#define CODA_ZAPFILE ((u_long) 27) -#define CODA_ZAPDIR ((u_long) 28) -#define CODA_ZAPVNODE ((u_long) 29) -#define CODA_PURGEFID ((u_long) 30) -#define CODA_NCALLS 31 +#define CODA_ROOT 2 +#define CODA_SYNC 3 +#define CODA_OPEN 4 +#define CODA_CLOSE 5 +#define CODA_IOCTL 6 +#define CODA_GETATTR 7 +#define CODA_SETATTR 8 +#define CODA_ACCESS 9 +#define CODA_LOOKUP 10 +#define CODA_CREATE 11 +#define CODA_REMOVE 12 +#define CODA_LINK 13 +#define CODA_RENAME 14 +#define CODA_MKDIR 15 +#define CODA_RMDIR 16 +#define CODA_READDIR 17 +#define CODA_SYMLINK 18 +#define CODA_READLINK 19 +#define CODA_FSYNC 20 +#define CODA_INACTIVE 21 +#define CODA_VGET 22 +#define CODA_SIGNAL 23 +#define CODA_REPLACE 24 +#define CODA_FLUSH 25 +#define CODA_PURGEUSER 26 +#define CODA_ZAPFILE 27 +#define CODA_ZAPDIR 28 +#define CODA_PURGEFID 30 +#define CODA_OPEN_BY_PATH 31 +#define CODA_RESOLVE 32 +#define CODA_REINTEGRATE 33 +#define CODA_NCALLS 34 #define DOWNCALL(opcode) (opcode >= CODA_REPLACE && opcode <= CODA_PURGEFID) #define VC_MAXDATASIZE 8192 #define VC_MAXMSGSIZE sizeof(union inputArgs)+sizeof(union outputArgs) +\ VC_MAXDATASIZE /* * Venus <-> Coda RPC arguments */ struct coda_in_hdr { unsigned long opcode; unsigned long unique; /* Keep multiple outstanding msgs distinct */ u_short pid; /* Common to all */ u_short pgid; /* Common to all */ u_short sid; /* Common to all */ struct coda_cred cred; /* Common to all */ }; /* Really important that opcode and unique are 1st two fields! */ struct coda_out_hdr { unsigned long opcode; unsigned long unique; unsigned long result; }; /* coda_root: NO_IN */ struct coda_root_out { struct coda_out_hdr oh; ViceFid VFid; }; struct coda_root_in { struct coda_in_hdr in; }; /* coda_sync: */ /* Nothing needed for coda_sync */ /* coda_open: */ struct coda_open_in { struct coda_in_hdr ih; ViceFid VFid; int flags; }; struct coda_open_out { struct coda_out_hdr oh; cdev_t dev; ino_t inode; }; /* coda_close: */ struct coda_close_in { struct coda_in_hdr ih; ViceFid VFid; int flags; }; struct coda_close_out { struct coda_out_hdr out; }; /* coda_ioctl: */ struct coda_ioctl_in { struct coda_in_hdr ih; ViceFid VFid; int cmd; int len; int rwflag; char *data; /* Place holder for data. */ }; struct coda_ioctl_out { struct coda_out_hdr oh; int len; caddr_t data; /* Place holder for data. */ }; /* coda_getattr: */ struct coda_getattr_in { struct coda_in_hdr ih; ViceFid VFid; }; struct coda_getattr_out { struct coda_out_hdr oh; struct coda_vattr attr; }; /* coda_setattr: NO_OUT */ struct coda_setattr_in { struct coda_in_hdr ih; ViceFid VFid; struct coda_vattr attr; }; struct coda_setattr_out { struct coda_out_hdr out; }; /* coda_access: NO_OUT */ struct coda_access_in { struct coda_in_hdr ih; ViceFid VFid; int flags; }; struct coda_access_out { struct coda_out_hdr out; }; /* coda_lookup: */ struct coda_lookup_in { struct coda_in_hdr ih; ViceFid VFid; int name; /* Place holder for data. */ }; struct coda_lookup_out { struct coda_out_hdr oh; ViceFid VFid; int vtype; }; /* coda_create: */ struct coda_create_in { struct coda_in_hdr ih; ViceFid VFid; struct coda_vattr attr; int excl; int mode; int name; /* Place holder for data. */ }; struct coda_create_out { struct coda_out_hdr oh; ViceFid VFid; struct coda_vattr attr; }; /* coda_remove: NO_OUT */ struct coda_remove_in { struct coda_in_hdr ih; ViceFid VFid; int name; /* Place holder for data. */ }; struct coda_remove_out { struct coda_out_hdr out; }; /* coda_link: NO_OUT */ struct coda_link_in { struct coda_in_hdr ih; ViceFid sourceFid; /* cnode to link *to* */ ViceFid destFid; /* Directory in which to place link */ int tname; /* Place holder for data. */ }; struct coda_link_out { struct coda_out_hdr out; }; /* coda_rename: NO_OUT */ struct coda_rename_in { struct coda_in_hdr ih; ViceFid sourceFid; int srcname; ViceFid destFid; int destname; }; struct coda_rename_out { struct coda_out_hdr out; }; /* coda_mkdir: */ struct coda_mkdir_in { struct coda_in_hdr ih; ViceFid VFid; struct coda_vattr attr; int name; /* Place holder for data. */ }; struct coda_mkdir_out { struct coda_out_hdr oh; ViceFid VFid; struct coda_vattr attr; }; /* coda_rmdir: NO_OUT */ struct coda_rmdir_in { struct coda_in_hdr ih; ViceFid VFid; int name; /* Place holder for data. */ }; struct coda_rmdir_out { struct coda_out_hdr out; }; /* coda_readdir: */ struct coda_readdir_in { struct coda_in_hdr ih; ViceFid VFid; int count; int offset; }; struct coda_readdir_out { struct coda_out_hdr oh; int size; caddr_t data; /* Place holder for data. */ }; /* coda_symlink: NO_OUT */ struct coda_symlink_in { struct coda_in_hdr ih; ViceFid VFid; /* Directory to put symlink in */ int srcname; struct coda_vattr attr; int tname; }; struct coda_symlink_out { struct coda_out_hdr out; }; /* coda_readlink: */ struct coda_readlink_in { struct coda_in_hdr ih; ViceFid VFid; }; struct coda_readlink_out { struct coda_out_hdr oh; int count; caddr_t data; /* Place holder for data. */ }; /* coda_fsync: NO_OUT */ struct coda_fsync_in { struct coda_in_hdr ih; ViceFid VFid; }; struct coda_fsync_out { struct coda_out_hdr out; }; /* coda_inactive: NO_OUT */ struct coda_inactive_in { struct coda_in_hdr ih; ViceFid VFid; }; /* coda_vget: */ struct coda_vget_in { struct coda_in_hdr ih; ViceFid VFid; }; struct coda_vget_out { struct coda_out_hdr oh; ViceFid VFid; int vtype; }; /* CODA_SIGNAL is out-of-band, doesn't need data. */ /* CODA_INVALIDATE is a venus->kernel call */ /* CODA_FLUSH is a venus->kernel call */ /* coda_purgeuser: */ /* CODA_PURGEUSER is a venus->kernel call */ struct coda_purgeuser_out { struct coda_out_hdr oh; struct coda_cred cred; }; /* coda_zapfile: */ /* CODA_ZAPFILE is a venus->kernel call */ struct coda_zapfile_out { struct coda_out_hdr oh; ViceFid CodaFid; }; /* coda_zapdir: */ /* CODA_ZAPDIR is a venus->kernel call */ struct coda_zapdir_out { struct coda_out_hdr oh; ViceFid CodaFid; }; /* coda_zapnode: */ /* CODA_ZAPVNODE is a venus->kernel call */ struct coda_zapvnode_out { struct coda_out_hdr oh; struct coda_cred cred; ViceFid VFid; }; /* coda_purgefid: */ /* CODA_PURGEFID is a venus->kernel call */ struct coda_purgefid_out { struct coda_out_hdr oh; ViceFid CodaFid; }; /* coda_rdwr: */ struct coda_rdwr_in { struct coda_in_hdr ih; ViceFid VFid; int rwflag; int count; int offset; int ioflag; caddr_t data; /* Place holder for data. */ }; struct coda_rdwr_out { struct coda_out_hdr oh; int rwflag; int count; caddr_t data; /* Place holder for data. */ }; /* coda_replace: */ /* CODA_REPLACE is a venus->kernel call */ struct coda_replace_out { /* coda_replace is a venus->kernel call */ struct coda_out_hdr oh; ViceFid NewFid; ViceFid OldFid; }; +/* coda_open_by_path: */ +struct coda_open_by_path_in { + struct coda_in_hdr ih; + ViceFid VFid; + int flags; +}; + +struct coda_open_by_path_out { + struct coda_out_hdr oh; + int path; +}; + /* - * Occasionally, don't cache the fid returned by CODA_LOOKUP. For instance, if - * the fid is inconsistent. This case is handled by setting the top bit of the - * return result parameter. + * Occasionally, we don't cache the fid returned by CODA_LOOKUP. + * For instance, if the fid is inconsistent. + * This case is handled by setting the top bit of the type result parameter. */ #define CODA_NOCACHE 0x80000000 union inputArgs { struct coda_in_hdr ih; /* NB: every struct below begins with an ih */ struct coda_open_in coda_open; struct coda_close_in coda_close; struct coda_ioctl_in coda_ioctl; struct coda_getattr_in coda_getattr; struct coda_setattr_in coda_setattr; struct coda_access_in coda_access; struct coda_lookup_in coda_lookup; struct coda_create_in coda_create; struct coda_remove_in coda_remove; struct coda_link_in coda_link; struct coda_rename_in coda_rename; struct coda_mkdir_in coda_mkdir; struct coda_rmdir_in coda_rmdir; struct coda_readdir_in coda_readdir; struct coda_symlink_in coda_symlink; struct coda_readlink_in coda_readlink; struct coda_fsync_in coda_fsync; struct coda_inactive_in coda_inactive; struct coda_vget_in coda_vget; struct coda_rdwr_in coda_rdwr; + struct coda_open_by_path_in coda_open_by_path; }; union outputArgs { struct coda_out_hdr oh; /* NB: every struct below begins with an oh */ struct coda_root_out coda_root; struct coda_open_out coda_open; struct coda_ioctl_out coda_ioctl; struct coda_getattr_out coda_getattr; struct coda_lookup_out coda_lookup; struct coda_create_out coda_create; struct coda_mkdir_out coda_mkdir; struct coda_readdir_out coda_readdir; struct coda_readlink_out coda_readlink; struct coda_vget_out coda_vget; struct coda_purgeuser_out coda_purgeuser; struct coda_zapfile_out coda_zapfile; struct coda_zapdir_out coda_zapdir; struct coda_zapvnode_out coda_zapvnode; struct coda_purgefid_out coda_purgefid; struct coda_rdwr_out coda_rdwr; struct coda_replace_out coda_replace; + struct coda_open_by_path_out coda_open_by_path; }; union coda_downcalls { /* CODA_INVALIDATE is a venus->kernel call */ /* CODA_FLUSH is a venus->kernel call */ struct coda_purgeuser_out purgeuser; struct coda_zapfile_out zapfile; struct coda_zapdir_out zapdir; struct coda_zapvnode_out zapvnode; struct coda_purgefid_out purgefid; struct coda_replace_out replace; }; /* * Used for identifying usage of "Control" and pioctls */ #define PIOCPARM_MASK 0x0000ffff struct ViceIoctl { caddr_t in, out; /* Data to be transferred in, or out */ short in_size; /* Size of input buffer <= 2K */ short out_size; /* Maximum size of output buffer, <= 2K */ }; struct PioctlData { const char *path; int follow; struct ViceIoctl vi; }; #define CODA_CONTROL ".CONTROL" #define CODA_CONTROLLEN 8 #define CTL_VOL -1 #define CTL_VNO -1 #define CTL_UNI -1 #define CTL_INO -1 #define CTL_FILE "/coda/.CONTROL" #define IS_CTL_FID(fidp) ((fidp)->Volume == CTL_VOL &&\ (fidp)->Vnode == CTL_VNO &&\ (fidp)->Unique == CTL_UNI) #endif Index: head/sys/fs/coda/coda_namecache.c =================================================================== --- head/sys/fs/coda/coda_namecache.c (revision 40705) +++ head/sys/fs/coda/coda_namecache.c (revision 40706) @@ -1,912 +1,915 @@ /* * * Coda: an Experimental Distributed File System * Release 3.1 * * Copyright (c) 1987-1998 Carnegie Mellon University * All Rights Reserved * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation, and * that credit is given to Carnegie Mellon University in all documents * and publicity pertaining to direct or indirect use of this code or its * derivatives. * * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS KNOWN TO HAVE BUGS, * SOME OF WHICH MAY HAVE SERIOUS CONSEQUENCES. CARNEGIE MELLON ALLOWS * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON * DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE OR OF * ANY DERIVATIVE WORK. * * Carnegie Mellon encourages users of this software to return any * improvements or extensions that they make, and to grant Carnegie * Mellon the rights to redistribute these changes without encumbrance. * * @(#) src/sys/coda/coda_namecache.c,v 1.1.1.1 1998/08/29 21:14:52 rvb Exp $ - * $Id: coda_namecache.c,v 1.6 1998/09/25 17:38:31 rvb Exp $ + * $Id: coda_namecache.c,v 1.7 1998/09/28 20:52:58 rvb Exp $ * */ /* * Mach Operating System * Copyright (c) 1990 Carnegie-Mellon University * Copyright (c) 1989 Carnegie-Mellon University * All rights reserved. The CMU software License Agreement specifies * the terms and conditions for use and redistribution. */ /* * This code was written for the Coda file system at Carnegie Mellon University. * Contributers include David Steere, James Kistler, and M. Satyanarayanan. */ /* * HISTORY * $Log: coda_namecache.c,v $ + * Revision 1.7 1998/09/28 20:52:58 rvb + * Cleanup and fix THE bug + * * Revision 1.6 1998/09/25 17:38:31 rvb * Put "stray" printouts under DIAGNOSTIC. Make everything build * with DEBUG on. Add support for lkm. (The macro's don't work * for me; for a good chuckle look at the end of coda_fbsd.c.) * * Revision 1.5 1998/09/13 13:57:59 rvb * Finish conversion of cfs -> coda * * Revision 1.4 1998/09/11 18:50:17 rvb * All the references to cfs, in symbols, structs, and strings * have been changed to coda. (Same for CFS.) * * Revision 1.2 1998/09/02 19:09:53 rvb * Pass2 complete * * Revision 1.1.1.1 1998/08/29 21:14:52 rvb * Very Preliminary Coda * * Revision 1.11 1998/08/28 18:12:16 rvb * Now it also works on FreeBSD -current. This code will be * committed to the FreeBSD -current and NetBSD -current * trees. It will then be tailored to the particular platform * by flushing conditional code. * * Revision 1.10 1998/08/18 17:05:14 rvb * Don't use __RCSID now * * Revision 1.9 1998/08/18 16:31:39 rvb * Sync the code for NetBSD -current; test on 1.3 later * * Revision 1.8 98/01/31 20:53:10 rvb * First version that works on FreeBSD 2.2.5 * * Revision 1.7 98/01/23 11:53:39 rvb * Bring RVB_CODA1_1 to HEAD * * Revision 1.6.2.4 98/01/23 11:21:02 rvb * Sync with 2.2.5 * * Revision 1.6.2.3 97/12/16 12:40:03 rvb * Sync with 1.3 * * Revision 1.6.2.2 97/12/09 16:07:10 rvb * Sync with vfs/include/coda.h * * Revision 1.6.2.1 97/12/06 17:41:18 rvb * Sync with peters coda.h * * Revision 1.6 97/12/05 10:39:13 rvb * Read CHANGES * * Revision 1.5.4.7 97/11/25 08:08:43 rvb * cfs_venus ... done; until cred/vattr change * * Revision 1.5.4.6 97/11/24 15:44:43 rvb * Final cfs_venus.c w/o macros, but one locking bug * * Revision 1.5.4.5 97/11/20 11:46:38 rvb * Capture current cfs_venus * * Revision 1.5.4.4 97/11/18 10:27:13 rvb * cfs_nbsd.c is DEAD!!!; integrated into cfs_vf/vnops.c * cfs_nb_foo and cfs_foo are joined * * Revision 1.5.4.3 97/11/13 22:02:57 rvb * pass2 cfs_NetBSD.h mt * * Revision 1.5.4.2 97/11/12 12:09:35 rvb * reorg pass1 * * Revision 1.5.4.1 97/10/28 23:10:12 rvb * >64Meg; venus can be killed! * * Revision 1.5 97/08/05 11:08:01 lily * Removed cfsnc_replace, replaced it with a coda_find, unhash, and * rehash. This fixes a cnode leak and a bug in which the fid is * not actually replaced. (cfs_namecache.c, cfsnc.h, cfs_subr.c) * * Revision 1.4 96/12/12 22:10:57 bnoble * Fixed the "downcall invokes venus operation" deadlock in all known cases. * There may be more * * Revision 1.3 1996/11/08 18:06:09 bnoble * Minor changes in vnode operation signature, VOP_UPDATE signature, and * some newly defined bits in the include files. * * Revision 1.2 1996/01/02 16:56:50 bnoble * Added support for Coda MiniCache and raw inode calls (final commit) * * Revision 1.1.2.1 1995/12/20 01:57:15 bnoble * Added CODA-specific files * * Revision 3.1.1.1 1995/03/04 19:07:57 bnoble * Branch for NetBSD port revisions * * Revision 3.1 1995/03/04 19:07:56 bnoble * Bump to major revision 3 to prepare for NetBSD port * * Revision 2.3 1994/10/14 09:57:54 dcs * Made changes 'cause sun4s have braindead compilers * * Revision 2.2 94/08/28 19:37:35 luqi * Add a new CODA_REPLACE call to allow venus to replace a ViceFid in the * mini-cache. * * In "cfs.h": * Add CODA_REPLACE decl. * * In "cfs_namecache.c": * Add routine cfsnc_replace. * * In "cfs_subr.c": * Add case-statement to process CODA_REPLACE. * * In "cfsnc.h": * Add decl for CODA_NC_REPLACE. * * * Revision 2.1 94/07/21 16:25:15 satya * Conversion to C++ 3.0; start of Coda Release 2.0 * * Revision 1.2 92/10/27 17:58:21 lily * merge kernel/latest and alpha/src/cfs * * Revision 2.3 92/09/30 14:16:20 mja * call coda_flush instead of calling inode_uncache_try directly * (from dcs). Also... * * Substituted rvb's history blurb so that we agree with Mach 2.5 sources. * [91/02/09 jjk] * * Added contributors blurb. * [90/12/13 jjk] * * Revision 2.2 90/07/05 11:26:30 mrt * Created for the Coda File System. * [90/05/23 dcs] * * Revision 1.3 90/05/31 17:01:24 dcs * Prepare for merge with facilities kernel. * * */ /* * This module contains the routines to implement the CODA name cache. The * purpose of this cache is to reduce the cost of translating pathnames * into Vice FIDs. Each entry in the cache contains the name of the file, * the vnode (FID) of the parent directory, and the cred structure of the * user accessing the file. * * The first time a file is accessed, it is looked up by the local Venus * which first insures that the user has access to the file. In addition * we are guaranteed that Venus will invalidate any name cache entries in * case the user no longer should be able to access the file. For these * reasons we do not need to keep access list information as well as a * cred structure for each entry. * * The table can be accessed through the routines cnc_init(), cnc_enter(), * cnc_lookup(), cnc_rmfidcred(), cnc_rmfid(), cnc_rmcred(), and cnc_purge(). * There are several other routines which aid in the implementation of the * hash table. */ /* * NOTES: rvb@cs * 1. The name cache holds a reference to every vnode in it. Hence files can not be * closed or made inactive until they are released. * 2. coda_nc_name(cp) was added to get a name for a cnode pointer for debugging. * 3. coda_nc_find() has debug code to detect when entries are stored with different * credentials. We don't understand yet, if/how entries are NOT EQ but still * EQUAL * 4. I wonder if this name cache could be replace by the vnode name cache. * The latter has no zapping functions, so probably not. */ #include #include #include #include #include #ifndef insque #include #endif /* insque */ #include #include #include #include #include #ifdef DEBUG #include #endif /* * Declaration of the name cache data structure. */ int coda_nc_use = 1; /* Indicate use of CODA Name Cache */ int coda_nc_size = CODA_NC_CACHESIZE; /* size of the cache */ int coda_nc_hashsize = CODA_NC_HASHSIZE; /* size of the primary hash */ struct coda_cache *coda_nc_heap; /* pointer to the cache entries */ struct coda_hash *coda_nc_hash; /* hash table of coda_cache pointers */ struct coda_lru coda_nc_lru; /* head of lru chain */ struct coda_nc_statistics coda_nc_stat; /* Keep various stats */ /* * for testing purposes */ int coda_nc_debug = 0; /* * Entry points for the CODA Name Cache */ static struct coda_cache *coda_nc_find(struct cnode *dcp, const char *name, int namelen, struct ucred *cred, int hash); static void coda_nc_remove(struct coda_cache *cncp, enum dc_status dcstat); /* * Initialize the cache, the LRU structure and the Hash structure(s) */ #define TOTAL_CACHE_SIZE (sizeof(struct coda_cache) * coda_nc_size) #define TOTAL_HASH_SIZE (sizeof(struct coda_hash) * coda_nc_hashsize) int coda_nc_initialized = 0; /* Initially the cache has not been initialized */ void coda_nc_init(void) { int i; /* zero the statistics structure */ bzero(&coda_nc_stat, (sizeof(struct coda_nc_statistics))); #ifdef CODA_VERBOSE printf("CODA NAME CACHE: CACHE %d, HASH TBL %d\n", CODA_NC_CACHESIZE, CODA_NC_HASHSIZE); #endif CODA_ALLOC(coda_nc_heap, struct coda_cache *, TOTAL_CACHE_SIZE); CODA_ALLOC(coda_nc_hash, struct coda_hash *, TOTAL_HASH_SIZE); coda_nc_lru.lru_next = coda_nc_lru.lru_prev = (struct coda_cache *)LRU_PART(&coda_nc_lru); for (i=0; i < coda_nc_size; i++) { /* initialize the heap */ CODA_NC_LRUINS(&coda_nc_heap[i], &coda_nc_lru); CODA_NC_HSHNUL(&coda_nc_heap[i]); coda_nc_heap[i].cp = coda_nc_heap[i].dcp = (struct cnode *)0; } for (i=0; i < coda_nc_hashsize; i++) { /* initialize the hashtable */ CODA_NC_HSHNUL((struct coda_cache *)&coda_nc_hash[i]); } coda_nc_initialized++; } /* * Auxillary routines -- shouldn't be entry points */ static struct coda_cache * coda_nc_find(dcp, name, namelen, cred, hash) struct cnode *dcp; const char *name; int namelen; struct ucred *cred; int hash; { /* * hash to find the appropriate bucket, look through the chain * for the right entry (especially right cred, unless cred == 0) */ struct coda_cache *cncp; int count = 1; CODA_NC_DEBUG(CODA_NC_FIND, myprintf(("coda_nc_find(dcp %p, name %s, len %d, cred %p, hash %d\n", dcp, name, namelen, cred, hash));) for (cncp = coda_nc_hash[hash].hash_next; cncp != (struct coda_cache *)&coda_nc_hash[hash]; cncp = cncp->hash_next, count++) { if ((CODA_NAMEMATCH(cncp, name, namelen, dcp)) && ((cred == 0) || (cncp->cred == cred))) { /* compare cr_uid instead */ coda_nc_stat.Search_len += count; return(cncp); } #ifdef DEBUG else if (CODA_NAMEMATCH(cncp, name, namelen, dcp)) { printf("coda_nc_find: name %s, new cred = %p, cred = %p\n", name, cred, cncp->cred); printf("nref %d, nuid %d, ngid %d // oref %d, ocred %d, ogid %d\n", cred->cr_ref, cred->cr_uid, cred->cr_gid, cncp->cred->cr_ref, cncp->cred->cr_uid, cncp->cred->cr_gid); print_cred(cred); print_cred(cncp->cred); } #endif } return((struct coda_cache *)0); } /* * Enter a new (dir cnode, name) pair into the cache, updating the * LRU and Hash as needed. */ void coda_nc_enter(dcp, name, namelen, cred, cp) struct cnode *dcp; const char *name; int namelen; struct ucred *cred; struct cnode *cp; { struct coda_cache *cncp; int hash; if (coda_nc_use == 0) /* Cache is off */ return; CODA_NC_DEBUG(CODA_NC_ENTER, myprintf(("Enter: dcp %p cp %p name %s cred %p \n", dcp, cp, name, cred)); ) if (namelen > CODA_NC_NAMELEN) { CODA_NC_DEBUG(CODA_NC_ENTER, myprintf(("long name enter %s\n",name));) coda_nc_stat.long_name_enters++; /* record stats */ return; } hash = CODA_NC_HASH(name, namelen, dcp); cncp = coda_nc_find(dcp, name, namelen, cred, hash); if (cncp != (struct coda_cache *) 0) { coda_nc_stat.dbl_enters++; /* duplicate entry */ return; } coda_nc_stat.enters++; /* record the enters statistic */ /* Grab the next element in the lru chain */ cncp = CODA_NC_LRUGET(coda_nc_lru); CODA_NC_LRUREM(cncp); /* remove it from the lists */ if (CODA_NC_VALID(cncp)) { /* Seems really ugly, but we have to decrement the appropriate hash bucket length here, so we have to find the hash bucket */ coda_nc_hash[CODA_NC_HASH(cncp->name, cncp->namelen, cncp->dcp)].length--; coda_nc_stat.lru_rm++; /* zapped a valid entry */ CODA_NC_HSHREM(cncp); vrele(CTOV(cncp->dcp)); vrele(CTOV(cncp->cp)); crfree(cncp->cred); } /* * Put a hold on the current vnodes and fill in the cache entry. */ vref(CTOV(cp)); vref(CTOV(dcp)); crhold(cred); cncp->dcp = dcp; cncp->cp = cp; cncp->namelen = namelen; cncp->cred = cred; bcopy(name, cncp->name, (unsigned)namelen); /* Insert into the lru and hash chains. */ CODA_NC_LRUINS(cncp, &coda_nc_lru); CODA_NC_HSHINS(cncp, &coda_nc_hash[hash]); coda_nc_hash[hash].length++; /* Used for tuning */ CODA_NC_DEBUG(CODA_NC_PRINTCODA_NC, print_coda_nc(); ) } /* * Find the (dir cnode, name) pair in the cache, if it's cred * matches the input, return it, otherwise return 0 */ struct cnode * coda_nc_lookup(dcp, name, namelen, cred) struct cnode *dcp; const char *name; int namelen; struct ucred *cred; { int hash; struct coda_cache *cncp; if (coda_nc_use == 0) /* Cache is off */ return((struct cnode *) 0); if (namelen > CODA_NC_NAMELEN) { CODA_NC_DEBUG(CODA_NC_LOOKUP, myprintf(("long name lookup %s\n",name));) coda_nc_stat.long_name_lookups++; /* record stats */ return((struct cnode *) 0); } /* Use the hash function to locate the starting point, then the search routine to go down the list looking for the correct cred. */ hash = CODA_NC_HASH(name, namelen, dcp); cncp = coda_nc_find(dcp, name, namelen, cred, hash); if (cncp == (struct coda_cache *) 0) { coda_nc_stat.misses++; /* record miss */ return((struct cnode *) 0); } coda_nc_stat.hits++; /* put this entry at the end of the LRU */ CODA_NC_LRUREM(cncp); CODA_NC_LRUINS(cncp, &coda_nc_lru); /* move it to the front of the hash chain */ /* don't need to change the hash bucket length */ CODA_NC_HSHREM(cncp); CODA_NC_HSHINS(cncp, &coda_nc_hash[hash]); CODA_NC_DEBUG(CODA_NC_LOOKUP, printf("lookup: dcp %p, name %s, cred %p = cp %p\n", dcp, name, cred, cncp->cp); ) return(cncp->cp); } static void coda_nc_remove(cncp, dcstat) struct coda_cache *cncp; enum dc_status dcstat; { /* * remove an entry -- vrele(cncp->dcp, cp), crfree(cred), * remove it from it's hash chain, and * place it at the head of the lru list. */ CODA_NC_DEBUG(CODA_NC_REMOVE, myprintf(("coda_nc_remove %s from parent %lx.%lx.%lx\n", cncp->name, (cncp->dcp)->c_fid.Volume, (cncp->dcp)->c_fid.Vnode, (cncp->dcp)->c_fid.Unique));) CODA_NC_HSHREM(cncp); CODA_NC_HSHNUL(cncp); /* have it be a null chain */ if ((dcstat == IS_DOWNCALL) && (CTOV(cncp->dcp)->v_usecount == 1)) { cncp->dcp->c_flags |= C_PURGING; } vrele(CTOV(cncp->dcp)); if ((dcstat == IS_DOWNCALL) && (CTOV(cncp->cp)->v_usecount == 1)) { cncp->cp->c_flags |= C_PURGING; } vrele(CTOV(cncp->cp)); crfree(cncp->cred); bzero(DATA_PART(cncp),DATA_SIZE); /* Put the null entry just after the least-recently-used entry */ /* LRU_TOP adjusts the pointer to point to the top of the structure. */ CODA_NC_LRUREM(cncp); CODA_NC_LRUINS(cncp, LRU_TOP(coda_nc_lru.lru_prev)); } /* * Remove all entries with a parent which has the input fid. */ void coda_nc_zapParentfid(fid, dcstat) ViceFid *fid; enum dc_status dcstat; { /* To get to a specific fid, we might either have another hashing function or do a sequential search through the cache for the appropriate entries. The later may be acceptable since I don't think callbacks or whatever Case 1 covers are frequent occurences. */ struct coda_cache *cncp, *ncncp; int i; if (coda_nc_use == 0) /* Cache is off */ return; CODA_NC_DEBUG(CODA_NC_ZAPPFID, myprintf(("ZapParent: fid 0x%lx, 0x%lx, 0x%lx \n", fid->Volume, fid->Vnode, fid->Unique)); ) coda_nc_stat.zapPfids++; for (i = 0; i < coda_nc_hashsize; i++) { /* * Need to save the hash_next pointer in case we remove the * entry. remove causes hash_next to point to itself. */ for (cncp = coda_nc_hash[i].hash_next; cncp != (struct coda_cache *)&coda_nc_hash[i]; cncp = ncncp) { ncncp = cncp->hash_next; if ((cncp->dcp->c_fid.Volume == fid->Volume) && (cncp->dcp->c_fid.Vnode == fid->Vnode) && (cncp->dcp->c_fid.Unique == fid->Unique)) { coda_nc_hash[i].length--; /* Used for tuning */ coda_nc_remove(cncp, dcstat); } } } } /* * Remove all entries which have the same fid as the input */ void coda_nc_zapfid(fid, dcstat) ViceFid *fid; enum dc_status dcstat; { /* See comment for zapParentfid. This routine will be used if attributes are being cached. */ struct coda_cache *cncp, *ncncp; int i; if (coda_nc_use == 0) /* Cache is off */ return; CODA_NC_DEBUG(CODA_NC_ZAPFID, myprintf(("Zapfid: fid 0x%lx, 0x%lx, 0x%lx \n", fid->Volume, fid->Vnode, fid->Unique)); ) coda_nc_stat.zapFids++; for (i = 0; i < coda_nc_hashsize; i++) { for (cncp = coda_nc_hash[i].hash_next; cncp != (struct coda_cache *)&coda_nc_hash[i]; cncp = ncncp) { ncncp = cncp->hash_next; if ((cncp->cp->c_fid.Volume == fid->Volume) && (cncp->cp->c_fid.Vnode == fid->Vnode) && (cncp->cp->c_fid.Unique == fid->Unique)) { coda_nc_hash[i].length--; /* Used for tuning */ coda_nc_remove(cncp, dcstat); } } } } /* * Remove all entries which match the fid and the cred */ void coda_nc_zapvnode(fid, cred, dcstat) ViceFid *fid; struct ucred *cred; enum dc_status dcstat; { /* See comment for zapfid. I don't think that one would ever want to zap a file with a specific cred from the kernel. We'll leave this one unimplemented. */ if (coda_nc_use == 0) /* Cache is off */ return; CODA_NC_DEBUG(CODA_NC_ZAPVNODE, myprintf(("Zapvnode: fid 0x%lx, 0x%lx, 0x%lx cred %p\n", fid->Volume, fid->Vnode, fid->Unique, cred)); ) } /* * Remove all entries which have the (dir vnode, name) pair */ void coda_nc_zapfile(dcp, name, namelen) struct cnode *dcp; const char *name; int namelen; { /* use the hash function to locate the file, then zap all entries of it regardless of the cred. */ struct coda_cache *cncp; int hash; if (coda_nc_use == 0) /* Cache is off */ return; CODA_NC_DEBUG(CODA_NC_ZAPFILE, myprintf(("Zapfile: dcp %p name %s \n", dcp, name)); ) if (namelen > CODA_NC_NAMELEN) { coda_nc_stat.long_remove++; /* record stats */ return; } coda_nc_stat.zapFile++; hash = CODA_NC_HASH(name, namelen, dcp); cncp = coda_nc_find(dcp, name, namelen, 0, hash); while (cncp) { coda_nc_hash[hash].length--; /* Used for tuning */ coda_nc_remove(cncp, NOT_DOWNCALL); cncp = coda_nc_find(dcp, name, namelen, 0, hash); } } /* * Remove all the entries for a particular user. Used when tokens expire. * A user is determined by his/her effective user id (id_uid). */ void coda_nc_purge_user(uid, dcstat) vuid_t uid; enum dc_status dcstat; { /* * I think the best approach is to go through the entire cache * via HASH or whatever and zap all entries which match the * input cred. Or just flush the whole cache. It might be * best to go through on basis of LRU since cache will almost * always be full and LRU is more straightforward. */ struct coda_cache *cncp, *ncncp; int hash; if (coda_nc_use == 0) /* Cache is off */ return; CODA_NC_DEBUG(CODA_NC_PURGEUSER, - myprintf(("ZapDude: uid %lx\n", uid)); ) + myprintf(("ZapDude: uid %x\n", uid)); ) coda_nc_stat.zapUsers++; for (cncp = CODA_NC_LRUGET(coda_nc_lru); cncp != (struct coda_cache *)(&coda_nc_lru); cncp = ncncp) { ncncp = CODA_NC_LRUGET(*cncp); if ((CODA_NC_VALID(cncp)) && ((cncp->cred)->cr_uid == uid)) { /* Seems really ugly, but we have to decrement the appropriate hash bucket length here, so we have to find the hash bucket */ hash = CODA_NC_HASH(cncp->name, cncp->namelen, cncp->dcp); coda_nc_hash[hash].length--; /* For performance tuning */ coda_nc_remove(cncp, dcstat); } } } /* * Flush the entire name cache. In response to a flush of the Venus cache. */ void coda_nc_flush(dcstat) enum dc_status dcstat; { /* One option is to deallocate the current name cache and call init to start again. Or just deallocate, then rebuild. Or again, we could just go through the array and zero the appropriate fields. */ /* * Go through the whole lru chain and kill everything as we go. * I don't use remove since that would rebuild the lru chain * as it went and that seemed unneccesary. */ struct coda_cache *cncp; int i; if (coda_nc_use == 0) /* Cache is off */ return; coda_nc_stat.Flushes++; for (cncp = CODA_NC_LRUGET(coda_nc_lru); cncp != (struct coda_cache *)&coda_nc_lru; cncp = CODA_NC_LRUGET(*cncp)) { if (CODA_NC_VALID(cncp)) { CODA_NC_HSHREM(cncp); /* only zero valid nodes */ CODA_NC_HSHNUL(cncp); if ((dcstat == IS_DOWNCALL) && (CTOV(cncp->dcp)->v_usecount == 1)) { cncp->dcp->c_flags |= C_PURGING; } vrele(CTOV(cncp->dcp)); if (CTOV(cncp->cp)->v_flag & VTEXT) { if (coda_vmflush(cncp->cp)) CODADEBUG(CODA_FLUSH, myprintf(("coda_nc_flush: (%lx.%lx.%lx) busy\n", cncp->cp->c_fid.Volume, cncp->cp->c_fid.Vnode, cncp->cp->c_fid.Unique)); ) } if ((dcstat == IS_DOWNCALL) && (CTOV(cncp->cp)->v_usecount == 1)) { cncp->cp->c_flags |= C_PURGING; } vrele(CTOV(cncp->cp)); crfree(cncp->cred); bzero(DATA_PART(cncp),DATA_SIZE); } } for (i = 0; i < coda_nc_hashsize; i++) coda_nc_hash[i].length = 0; } /* * Debugging routines */ /* * This routine should print out all the hash chains to the console. */ void print_coda_nc(void) { int hash; struct coda_cache *cncp; for (hash = 0; hash < coda_nc_hashsize; hash++) { myprintf(("\nhash %d\n",hash)); for (cncp = coda_nc_hash[hash].hash_next; cncp != (struct coda_cache *)&coda_nc_hash[hash]; cncp = cncp->hash_next) { myprintf(("cp %p dcp %p cred %p name %s\n", cncp->cp, cncp->dcp, cncp->cred, cncp->name)); } } } void coda_nc_gather_stats(void) { int i, max = 0, sum = 0, temp, zeros = 0, ave, n; for (i = 0; i < coda_nc_hashsize; i++) { if (coda_nc_hash[i].length) { sum += coda_nc_hash[i].length; } else { zeros++; } if (coda_nc_hash[i].length > max) max = coda_nc_hash[i].length; } /* * When computing the Arithmetic mean, only count slots which * are not empty in the distribution. */ coda_nc_stat.Sum_bucket_len = sum; coda_nc_stat.Num_zero_len = zeros; coda_nc_stat.Max_bucket_len = max; if ((n = coda_nc_hashsize - zeros) > 0) ave = sum / n; else ave = 0; sum = 0; for (i = 0; i < coda_nc_hashsize; i++) { if (coda_nc_hash[i].length) { temp = coda_nc_hash[i].length - ave; sum += temp * temp; } } coda_nc_stat.Sum2_bucket_len = sum; } /* * The purpose of this routine is to allow the hash and cache sizes to be * changed dynamically. This should only be used in controlled environments, * it makes no effort to lock other users from accessing the cache while it * is in an improper state (except by turning the cache off). */ int coda_nc_resize(hashsize, heapsize, dcstat) int hashsize, heapsize; enum dc_status dcstat; { if ((hashsize % 2) || (heapsize % 2)) { /* Illegal hash or cache sizes */ return(EINVAL); } coda_nc_use = 0; /* Turn the cache off */ coda_nc_flush(dcstat); /* free any cnodes in the cache */ /* WARNING: free must happen *before* size is reset */ CODA_FREE(coda_nc_heap,TOTAL_CACHE_SIZE); CODA_FREE(coda_nc_hash,TOTAL_HASH_SIZE); coda_nc_hashsize = hashsize; coda_nc_size = heapsize; coda_nc_init(); /* Set up a cache with the new size */ coda_nc_use = 1; /* Turn the cache back on */ return(0); } #ifdef DEBUG char coda_nc_name_buf[CODA_MAXNAMLEN+1]; void coda_nc_name(struct cnode *cp) { struct coda_cache *cncp, *ncncp; int i; if (coda_nc_use == 0) /* Cache is off */ return; for (i = 0; i < coda_nc_hashsize; i++) { for (cncp = coda_nc_hash[i].hash_next; cncp != (struct coda_cache *)&coda_nc_hash[i]; cncp = ncncp) { ncncp = cncp->hash_next; if (cncp->cp == cp) { bcopy(cncp->name, coda_nc_name_buf, cncp->namelen); coda_nc_name_buf[cncp->namelen] = 0; printf(" is %s (%p,%p)@%p", coda_nc_name_buf, cncp->cp, cncp->dcp, cncp); } } } } #endif Index: head/sys/fs/coda/coda_subr.c =================================================================== --- head/sys/fs/coda/coda_subr.c (revision 40705) +++ head/sys/fs/coda/coda_subr.c (revision 40706) @@ -1,756 +1,745 @@ /* * * Coda: an Experimental Distributed File System * Release 3.1 * * Copyright (c) 1987-1998 Carnegie Mellon University * All Rights Reserved * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation, and * that credit is given to Carnegie Mellon University in all documents * and publicity pertaining to direct or indirect use of this code or its * derivatives. * * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS KNOWN TO HAVE BUGS, * SOME OF WHICH MAY HAVE SERIOUS CONSEQUENCES. CARNEGIE MELLON ALLOWS * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON * DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE OR OF * ANY DERIVATIVE WORK. * * Carnegie Mellon encourages users of this software to return any * improvements or extensions that they make, and to grant Carnegie * Mellon the rights to redistribute these changes without encumbrance. * * @(#) src/sys/coda/coda_subr.c,v 1.1.1.1 1998/08/29 21:14:52 rvb Exp $ - * $Id: coda_subr.c,v 1.6 1998/09/25 17:38:31 rvb Exp $ + * $Id: coda_subr.c,v 1.7 1998/09/29 20:19:45 rvb Exp $ * */ /* * Mach Operating System * Copyright (c) 1989 Carnegie-Mellon University * All rights reserved. The CMU software License Agreement specifies * the terms and conditions for use and redistribution. */ /* * This code was written for the Coda file system at Carnegie Mellon * University. Contributers include David Steere, James Kistler, and * M. Satyanarayanan. */ /* * HISTORY * $Log: coda_subr.c,v $ + * Revision 1.7 1998/09/29 20:19:45 rvb + * Fixes for lkm: + * 1. use VFS_LKM vs ACTUALLY_LKM_NOT_KERNEL + * 2. don't pass -DCODA to lkm build + * * Revision 1.6 1998/09/25 17:38:31 rvb * Put "stray" printouts under DIAGNOSTIC. Make everything build * with DEBUG on. Add support for lkm. (The macro's don't work * for me; for a good chuckle look at the end of coda_fbsd.c.) * * Revision 1.5 1998/09/13 13:57:59 rvb * Finish conversion of cfs -> coda * * Revision 1.4 1998/09/11 18:50:17 rvb * All the references to cfs, in symbols, structs, and strings * have been changed to coda. (Same for CFS.) * * Revision 1.2 1998/09/02 19:09:53 rvb * Pass2 complete * * Revision 1.1.1.1 1998/08/29 21:14:52 rvb * Very Preliminary Coda * * Revision 1.11 1998/08/28 18:12:18 rvb * Now it also works on FreeBSD -current. This code will be * committed to the FreeBSD -current and NetBSD -current * trees. It will then be tailored to the particular platform * by flushing conditional code. * * Revision 1.10 1998/08/18 17:05:16 rvb * Don't use __RCSID now * * Revision 1.9 1998/08/18 16:31:41 rvb * Sync the code for NetBSD -current; test on 1.3 later * * Revision 1.8 98/01/31 20:53:12 rvb * First version that works on FreeBSD 2.2.5 * * Revision 1.7 98/01/23 11:53:42 rvb * Bring RVB_CODA1_1 to HEAD * * Revision 1.6.2.3 98/01/23 11:21:05 rvb * Sync with 2.2.5 * * Revision 1.6.2.2 97/12/16 12:40:06 rvb * Sync with 1.3 * * Revision 1.6.2.1 97/12/06 17:41:21 rvb * Sync with peters coda.h * * Revision 1.6 97/12/05 10:39:17 rvb * Read CHANGES * * Revision 1.5.4.8 97/11/26 15:28:58 rvb * Cant make downcall pbuf == union cfs_downcalls yet * * Revision 1.5.4.7 97/11/20 11:46:42 rvb * Capture current cfs_venus * * Revision 1.5.4.6 97/11/18 10:27:16 rvb * cfs_nbsd.c is DEAD!!!; integrated into cfs_vf/vnops.c * cfs_nb_foo and cfs_foo are joined * * Revision 1.5.4.5 97/11/13 22:03:00 rvb * pass2 cfs_NetBSD.h mt * * Revision 1.5.4.4 97/11/12 12:09:39 rvb * reorg pass1 * * Revision 1.5.4.3 97/11/06 21:02:38 rvb * first pass at ^c ^z * * Revision 1.5.4.2 97/10/29 16:06:27 rvb * Kill DYING * * Revision 1.5.4.1 97/10/28 23:10:16 rvb * >64Meg; venus can be killed! * * Revision 1.5 97/08/05 11:08:17 lily * Removed cfsnc_replace, replaced it with a coda_find, unhash, and * rehash. This fixes a cnode leak and a bug in which the fid is * not actually replaced. (cfs_namecache.c, cfsnc.h, cfs_subr.c) * * Revision 1.4 96/12/12 22:10:59 bnoble * Fixed the "downcall invokes venus operation" deadlock in all known cases. * There may be more * * Revision 1.3 1996/12/05 16:20:15 bnoble * Minor debugging aids * * Revision 1.2 1996/01/02 16:57:01 bnoble * Added support for Coda MiniCache and raw inode calls (final commit) * * Revision 1.1.2.1 1995/12/20 01:57:27 bnoble * Added CODA-specific files * * Revision 3.1.1.1 1995/03/04 19:07:59 bnoble * Branch for NetBSD port revisions * * Revision 3.1 1995/03/04 19:07:58 bnoble * Bump to major revision 3 to prepare for NetBSD port * * Revision 2.8 1995/03/03 17:00:04 dcs * Fixed kernel bug involving sleep and upcalls. Basically if you killed * a job waiting on venus, the venus upcall queues got trashed. Depending * on luck, you could kill the kernel or not. * (mods to cfs_subr.c and cfs_mach.d) * * Revision 2.7 95/03/02 22:45:21 dcs * Sun4 compatibility * * Revision 2.6 95/02/17 16:25:17 dcs * These versions represent several changes: * 1. Allow venus to restart even if outstanding references exist. * 2. Have only one ctlvp per client, as opposed to one per mounted cfs device.d * 3. Allow ody_expand to return many members, not just one. * * Revision 2.5 94/11/09 15:56:26 dcs * Had the thread sleeping on the wrong thing! * * Revision 2.4 94/10/14 09:57:57 dcs * Made changes 'cause sun4s have braindead compilers * * Revision 2.3 94/10/12 16:46:26 dcs * Cleaned kernel/venus interface by removing XDR junk, plus * so cleanup to allow this code to be more easily ported. * * Revision 1.2 92/10/27 17:58:22 lily * merge kernel/latest and alpha/src/cfs * * Revision 2.4 92/09/30 14:16:26 mja * Incorporated Dave Steere's fix for the GNU-Emacs bug. * Also, included his coda_flush routine in place of the former coda_nc_flush. * [91/02/07 jjk] * * Added contributors blurb. * [90/12/13 jjk] * * Hack to allow users to keep coda venus calls uninterruptible. THis * basically prevents the Gnu-emacs bug from appearing, in which a call * was being interrupted, and return EINTR, but gnu didn't check for the * error and figured the file was buggered. * [90/12/09 dcs] * * Revision 2.3 90/08/10 10:23:20 mrt * Removed include of vm/vm_page.h as it no longer exists. * [90/08/10 mrt] * * Revision 2.2 90/07/05 11:26:35 mrt * Initialize name cache on first call to vcopen. * [90/05/23 dcs] * * Created for the Coda File System. * [90/05/23 dcs] * * Revision 1.5 90/05/31 17:01:35 dcs * Prepare for merge with facilities kernel. * * Revision 1.2 90/03/19 15:56:25 dcs * Initialize name cache on first call to vcopen. * * Revision 1.1 90/03/15 10:43:26 jjk * Initial revision * */ /* NOTES: rvb * 1. Added coda_unmounting to mark all cnodes as being UNMOUNTING. This has to * be done before dounmount is called. Because some of the routines that * dounmount calls before coda_unmounted might try to force flushes to venus. * The vnode pager does this. * 2. coda_unmounting marks all cnodes scanning coda_cache. * 3. cfs_checkunmounting (under DEBUG) checks all cnodes by chasing the vnodes * under the /coda mount point. * 4. coda_cacheprint (under DEBUG) prints names with vnode/cnode address */ #ifdef VFS_LKM #define NVCODA 4 #else #include #endif #include #include #include #include #include #include #include #include #include #include int coda_active = 0; int coda_reuse = 0; int coda_new = 0; struct cnode *coda_freelist = NULL; struct cnode *coda_cache[CODA_CACHESIZE]; #define coda_hash(fid) (((fid)->Volume + (fid)->Vnode) & (CODA_CACHESIZE-1)) #define CNODE_NEXT(cp) ((cp)->c_next) #define ODD(vnode) ((vnode) & 0x1) /* * Allocate a cnode. */ struct cnode * coda_alloc(void) { struct cnode *cp; if (coda_freelist) { cp = coda_freelist; coda_freelist = CNODE_NEXT(cp); coda_reuse++; } else { CODA_ALLOC(cp, struct cnode *, sizeof(struct cnode)); /* NetBSD vnodes don't have any Pager info in them ('cause there are no external pagers, duh!) */ #define VNODE_VM_INFO_INIT(vp) /* MT */ VNODE_VM_INFO_INIT(CTOV(cp)); coda_new++; } bzero(cp, sizeof (struct cnode)); return(cp); } /* * Deallocate a cnode. */ void coda_free(cp) register struct cnode *cp; { CNODE_NEXT(cp) = coda_freelist; coda_freelist = cp; } /* * Put a cnode in the hash table */ void coda_save(cp) struct cnode *cp; { CNODE_NEXT(cp) = coda_cache[coda_hash(&cp->c_fid)]; coda_cache[coda_hash(&cp->c_fid)] = cp; } /* * Remove a cnode from the hash table */ void coda_unsave(cp) struct cnode *cp; { struct cnode *ptr; struct cnode *ptrprev = NULL; ptr = coda_cache[coda_hash(&cp->c_fid)]; while (ptr != NULL) { if (ptr == cp) { if (ptrprev == NULL) { coda_cache[coda_hash(&cp->c_fid)] = CNODE_NEXT(ptr); } else { CNODE_NEXT(ptrprev) = CNODE_NEXT(ptr); } CNODE_NEXT(cp) = (struct cnode *)NULL; return; } ptrprev = ptr; ptr = CNODE_NEXT(ptr); } } /* * Lookup a cnode by fid. If the cnode is dying, it is bogus so skip it. * NOTE: this allows multiple cnodes with same fid -- dcs 1/25/95 */ struct cnode * coda_find(fid) ViceFid *fid; { struct cnode *cp; cp = coda_cache[coda_hash(fid)]; while (cp) { if ((cp->c_fid.Vnode == fid->Vnode) && (cp->c_fid.Volume == fid->Volume) && (cp->c_fid.Unique == fid->Unique) && (!IS_UNMOUNTING(cp))) { coda_active++; return(cp); } cp = CNODE_NEXT(cp); } return(NULL); } /* * coda_kill is called as a side effect to vcopen. To prevent any * cnodes left around from an earlier run of a venus or warden from * causing problems with the new instance, mark any outstanding cnodes * as dying. Future operations on these cnodes should fail (excepting * coda_inactive of course!). Since multiple venii/wardens can be * running, only kill the cnodes for a particular entry in the * coda_mnttbl. -- DCS 12/1/94 */ int coda_kill(whoIam, dcstat) struct mount *whoIam; enum dc_status dcstat; { int hash, count = 0; struct cnode *cp; /* * Algorithm is as follows: * Second, flush whatever vnodes we can from the name cache. * * Finally, step through whatever is left and mark them dying. * This prevents any operation at all. */ /* This is slightly overkill, but should work. Eventually it'd be * nice to only flush those entries from the namecache that * reference a vnode in this vfs. */ coda_nc_flush(dcstat); for (hash = 0; hash < CODA_CACHESIZE; hash++) { for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) { if (CTOV(cp)->v_mount == whoIam) { #ifdef DEBUG printf("coda_kill: vp %p, cp %p\n", CTOV(cp), cp); #endif count++; CODADEBUG(CODA_FLUSH, myprintf(("Live cnode fid %lx.%lx.%lx flags %d count %d\n", (cp->c_fid).Volume, (cp->c_fid).Vnode, (cp->c_fid).Unique, cp->c_flags, CTOV(cp)->v_usecount)); ); } } } return count; } /* * There are two reasons why a cnode may be in use, it may be in the * name cache or it may be executing. */ void coda_flush(dcstat) enum dc_status dcstat; { int hash; struct cnode *cp; coda_clstat.ncalls++; coda_clstat.reqs[CODA_FLUSH]++; coda_nc_flush(dcstat); /* flush files from the name cache */ for (hash = 0; hash < CODA_CACHESIZE; hash++) { for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) { if (!ODD(cp->c_fid.Vnode)) /* only files can be executed */ coda_vmflush(cp); } } } /* * As a debugging measure, print out any cnodes that lived through a * name cache flush. */ void coda_testflush(void) { int hash; struct cnode *cp; for (hash = 0; hash < CODA_CACHESIZE; hash++) { for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) { myprintf(("Live cnode fid %lx.%lx.%lx count %d\n", (cp->c_fid).Volume,(cp->c_fid).Vnode, (cp->c_fid).Unique, CTOV(cp)->v_usecount)); } } } /* * First, step through all cnodes and mark them unmounting. * NetBSD kernels may try to fsync them now that venus * is dead, which would be a bad thing. * */ void coda_unmounting(whoIam) struct mount *whoIam; { int hash; struct cnode *cp; for (hash = 0; hash < CODA_CACHESIZE; hash++) { for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) { if (CTOV(cp)->v_mount == whoIam) { if (cp->c_flags & (C_LOCKED|C_WANTED)) { printf("coda_unmounting: Unlocking %p\n", cp); cp->c_flags &= ~(C_LOCKED|C_WANTED); wakeup((caddr_t) cp); } cp->c_flags |= C_UNMOUNTING; } } } } #ifdef DEBUG void coda_checkunmounting(mp) struct mount *mp; { register struct vnode *vp, *nvp; struct cnode *cp; int count = 0, bad = 0; loop: for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) { if (vp->v_mount != mp) goto loop; nvp = vp->v_mntvnodes.le_next; cp = VTOC(vp); count++; if (!(cp->c_flags & C_UNMOUNTING)) { bad++; printf("vp %p, cp %p missed\n", vp, cp); cp->c_flags |= C_UNMOUNTING; } } } void coda_cacheprint(whoIam) struct mount *whoIam; { int hash; struct cnode *cp; int count = 0; printf("coda_cacheprint: coda_ctlvp %p, cp %p", coda_ctlvp, VTOC(coda_ctlvp)); coda_nc_name(VTOC(coda_ctlvp)); printf("\n"); for (hash = 0; hash < CODA_CACHESIZE; hash++) { for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) { if (CTOV(cp)->v_mount == whoIam) { printf("coda_cacheprint: vp %p, cp %p", CTOV(cp), cp); coda_nc_name(cp); printf("\n"); count++; } } } printf("coda_cacheprint: count %d\n", count); } #endif /* * There are 6 cases where invalidations occur. The semantics of each * is listed here. * * CODA_FLUSH -- flush all entries from the name cache and the cnode cache. * CODA_PURGEUSER -- flush all entries from the name cache for a specific user * This call is a result of token expiration. * * The next two are the result of callbacks on a file or directory. * CODA_ZAPDIR -- flush the attributes for the dir from its cnode. * Zap all children of this directory from the namecache. * CODA_ZAPFILE -- flush the attributes for a file. * * The fifth is a result of Venus detecting an inconsistent file. * CODA_PURGEFID -- flush the attribute for the file * If it is a dir (odd vnode), purge its * children from the namecache * remove the file from the namecache. * * The sixth allows Venus to replace local fids with global ones * during reintegration. * * CODA_REPLACE -- replace one ViceFid with another throughout the name cache */ int handleDownCall(opcode, out) int opcode; union outputArgs *out; { int error; /* Handle invalidate requests. */ switch (opcode) { case CODA_FLUSH : { coda_flush(IS_DOWNCALL); CODADEBUG(CODA_FLUSH,coda_testflush();) /* print remaining cnodes */ return(0); } case CODA_PURGEUSER : { coda_clstat.ncalls++; coda_clstat.reqs[CODA_PURGEUSER]++; /* XXX - need to prevent fsync's */ coda_nc_purge_user(out->coda_purgeuser.cred.cr_uid, IS_DOWNCALL); return(0); } case CODA_ZAPFILE : { struct cnode *cp; error = 0; coda_clstat.ncalls++; coda_clstat.reqs[CODA_ZAPFILE]++; cp = coda_find(&out->coda_zapfile.CodaFid); if (cp != NULL) { vref(CTOV(cp)); cp->c_flags &= ~C_VATTR; if (CTOV(cp)->v_flag & VTEXT) error = coda_vmflush(cp); CODADEBUG(CODA_ZAPFILE, myprintf(("zapfile: fid = (%lx.%lx.%lx), refcnt = %d, error = %d\n", cp->c_fid.Volume, cp->c_fid.Vnode, cp->c_fid.Unique, CTOV(cp)->v_usecount - 1, error));); if (CTOV(cp)->v_usecount == 1) { cp->c_flags |= C_PURGING; } vrele(CTOV(cp)); } return(error); } case CODA_ZAPDIR : { struct cnode *cp; coda_clstat.ncalls++; coda_clstat.reqs[CODA_ZAPDIR]++; cp = coda_find(&out->coda_zapdir.CodaFid); if (cp != NULL) { vref(CTOV(cp)); cp->c_flags &= ~C_VATTR; coda_nc_zapParentfid(&out->coda_zapdir.CodaFid, IS_DOWNCALL); CODADEBUG(CODA_ZAPDIR, myprintf(("zapdir: fid = (%lx.%lx.%lx), refcnt = %d\n",cp->c_fid.Volume, cp->c_fid.Vnode, cp->c_fid.Unique, CTOV(cp)->v_usecount - 1));); if (CTOV(cp)->v_usecount == 1) { cp->c_flags |= C_PURGING; } vrele(CTOV(cp)); } return(0); } - - case CODA_ZAPVNODE : { - coda_clstat.ncalls++; - coda_clstat.reqs[CODA_ZAPVNODE]++; - - myprintf(("CODA_ZAPVNODE: Called, but uniplemented\n")); - /* - * Not that below we must really translate the returned coda_cred to - * a netbsd cred. This is a bit muddled at present and the cfsnc_zapnode - * is further unimplemented, so punt! - * I suppose we could use just the uid. - */ - /* coda_nc_zapvnode(&out->coda_zapvnode.VFid, &out->coda_zapvnode.cred, - IS_DOWNCALL); */ - return(0); - } case CODA_PURGEFID : { struct cnode *cp; error = 0; coda_clstat.ncalls++; coda_clstat.reqs[CODA_PURGEFID]++; cp = coda_find(&out->coda_purgefid.CodaFid); if (cp != NULL) { vref(CTOV(cp)); if (ODD(out->coda_purgefid.CodaFid.Vnode)) { /* Vnode is a directory */ coda_nc_zapParentfid(&out->coda_purgefid.CodaFid, IS_DOWNCALL); } cp->c_flags &= ~C_VATTR; coda_nc_zapfid(&out->coda_purgefid.CodaFid, IS_DOWNCALL); if (!(ODD(out->coda_purgefid.CodaFid.Vnode)) && (CTOV(cp)->v_flag & VTEXT)) { error = coda_vmflush(cp); } CODADEBUG(CODA_PURGEFID, myprintf(("purgefid: fid = (%lx.%lx.%lx), refcnt = %d, error = %d\n", cp->c_fid.Volume, cp->c_fid.Vnode, cp->c_fid.Unique, CTOV(cp)->v_usecount - 1, error));); if (CTOV(cp)->v_usecount == 1) { cp->c_flags |= C_PURGING; } vrele(CTOV(cp)); } return(error); } case CODA_REPLACE : { struct cnode *cp = NULL; coda_clstat.ncalls++; coda_clstat.reqs[CODA_REPLACE]++; cp = coda_find(&out->coda_replace.OldFid); if (cp != NULL) { /* remove the cnode from the hash table, replace the fid, and reinsert */ vref(CTOV(cp)); coda_unsave(cp); cp->c_fid = out->coda_replace.NewFid; coda_save(cp); CODADEBUG(CODA_REPLACE, myprintf(("replace: oldfid = (%lx.%lx.%lx), newfid = (%lx.%lx.%lx), cp = %p\n", out->coda_replace.OldFid.Volume, out->coda_replace.OldFid.Vnode, out->coda_replace.OldFid.Unique, cp->c_fid.Volume, cp->c_fid.Vnode, cp->c_fid.Unique, cp));) vrele(CTOV(cp)); } return (0); } default: myprintf(("handleDownCall: unknown opcode %d\n", opcode)); return (EINVAL); } } /* coda_grab_vnode: lives in either cfs_mach.c or cfs_nbsd.c */ int coda_vmflush(cp) struct cnode *cp; { return 0; } /* * kernel-internal debugging switches */ void coda_debugon(void) { codadebug = -1; coda_nc_debug = -1; coda_vnop_print_entry = 1; coda_psdev_print_entry = 1; coda_vfsop_print_entry = 1; } void coda_debugoff(void) { codadebug = 0; coda_nc_debug = 0; coda_vnop_print_entry = 0; coda_psdev_print_entry = 0; coda_vfsop_print_entry = 0; } /* * Utilities used by both client and server * Standard levels: * 0) no debugging * 1) hard failures * 2) soft failures * 3) current test software * 4) main procedure entry points * 5) main procedure exit points * 6) utility procedure entry points * 7) utility procedure exit points * 8) obscure procedure entry points * 9) obscure procedure exit points * 10) random stuff * 11) all <= 1 * 12) all <= 2 * 13) all <= 3 * ... */ Index: head/sys/fs/coda/coda_venus.c =================================================================== --- head/sys/fs/coda/coda_venus.c (revision 40705) +++ head/sys/fs/coda/coda_venus.c (revision 40706) @@ -1,647 +1,648 @@ /* * * Coda: an Experimental Distributed File System * Release 3.1 * * Copyright (c) 1987-1998 Carnegie Mellon University * All Rights Reserved * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation, and * that credit is given to Carnegie Mellon University in all documents * and publicity pertaining to direct or indirect use of this code or its * derivatives. * * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS KNOWN TO HAVE BUGS, * SOME OF WHICH MAY HAVE SERIOUS CONSEQUENCES. CARNEGIE MELLON ALLOWS * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON * DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE OR OF * ANY DERIVATIVE WORK. * * Carnegie Mellon encourages users of this software to return any * improvements or extensions that they make, and to grant Carnegie * Mellon the rights to redistribute these changes without encumbrance. * * @(#) src/sys/cfs/coda_venus.c,v 1.1.1.1 1998/08/29 21:14:52 rvb Exp $ - * $Id: coda_venus.c,v 1.3 1998/09/11 18:50:17 rvb Exp $ + * $Id: coda_venus.c,v 1.4 1998/09/13 13:57:59 rvb Exp $ * */ #include #include #include #include #include #include #include #include #include #include #include #define DECL_NO_IN(name) \ struct coda_in_hdr *inp; \ struct name ## _out *outp; \ int name ## _size = sizeof (struct coda_in_hdr); \ int Isize = sizeof (struct coda_in_hdr); \ int Osize = sizeof (struct name ## _out); \ int error #define DECL(name) \ struct name ## _in *inp; \ struct name ## _out *outp; \ int name ## _size = sizeof (struct name ## _in); \ int Isize = sizeof (struct name ## _in); \ int Osize = sizeof (struct name ## _out); \ int error #define DECL_NO_OUT(name) \ struct name ## _in *inp; \ struct coda_out_hdr *outp; \ int name ## _size = sizeof (struct name ## _in); \ int Isize = sizeof (struct name ## _in); \ int Osize = sizeof (struct coda_out_hdr); \ int error #define ALLOC_NO_IN(name) \ if (Osize > name ## _size) \ name ## _size = Osize; \ CODA_ALLOC(inp, struct coda_in_hdr *, name ## _size);\ outp = (struct name ## _out *) inp #define ALLOC(name) \ if (Osize > name ## _size) \ name ## _size = Osize; \ CODA_ALLOC(inp, struct name ## _in *, name ## _size);\ outp = (struct name ## _out *) inp #define ALLOC_NO_OUT(name) \ if (Osize > name ## _size) \ name ## _size = Osize; \ CODA_ALLOC(inp, struct name ## _in *, name ## _size);\ outp = (struct coda_out_hdr *) inp #define STRCPY(struc, name, len) \ bcopy(name, (char *)inp + (int)inp->struc, len); \ ((char*)inp + (int)inp->struc)[len++] = 0; \ Isize += len #define INIT_IN(in, op, ident, p) \ (in)->opcode = (op); \ (in)->pid = p ? p->p_pid : -1; \ (in)->pgid = p ? p->p_pgid : -1; \ (in)->sid = (p && p->p_session && p->p_session->s_leader) ? (p->p_session->s_leader->p_pid) : -1; \ if (ident != NOCRED) { \ (in)->cred.cr_uid = ident->cr_uid; \ (in)->cred.cr_groupid = ident->cr_gid; \ } else { \ bzero(&((in)->cred),sizeof(struct coda_cred)); \ (in)->cred.cr_uid = -1; \ (in)->cred.cr_groupid = -1; \ } \ #define CNV_OFLAG(to, from) \ do { \ to = 0; \ if (from & FREAD) to |= C_O_READ; \ if (from & FWRITE) to |= C_O_WRITE; \ if (from & O_TRUNC) to |= C_O_TRUNC; \ if (from & O_EXCL) to |= C_O_EXCL; \ + if (from & O_CREAT) to |= C_O_CREAT; \ } while (0) #define CNV_VV2V_ATTR(top, fromp) \ do { \ (top)->va_type = (fromp)->va_type; \ (top)->va_mode = (fromp)->va_mode; \ (top)->va_nlink = (fromp)->va_nlink; \ (top)->va_uid = (fromp)->va_uid; \ (top)->va_gid = (fromp)->va_gid; \ (top)->va_fsid = VNOVAL; \ (top)->va_fileid = (fromp)->va_fileid; \ (top)->va_size = (fromp)->va_size; \ (top)->va_blocksize = (fromp)->va_blocksize; \ (top)->va_atime = (fromp)->va_atime; \ (top)->va_mtime = (fromp)->va_mtime; \ (top)->va_ctime = (fromp)->va_ctime; \ (top)->va_gen = (fromp)->va_gen; \ (top)->va_flags = (fromp)->va_flags; \ (top)->va_rdev = (fromp)->va_rdev; \ (top)->va_bytes = (fromp)->va_bytes; \ (top)->va_filerev = (fromp)->va_filerev; \ (top)->va_vaflags = VNOVAL; \ (top)->va_spare = VNOVAL; \ } while (0) #define CNV_V2VV_ATTR(top, fromp) \ do { \ (top)->va_type = (fromp)->va_type; \ (top)->va_mode = (fromp)->va_mode; \ (top)->va_nlink = (fromp)->va_nlink; \ (top)->va_uid = (fromp)->va_uid; \ (top)->va_gid = (fromp)->va_gid; \ (top)->va_fileid = (fromp)->va_fileid; \ (top)->va_size = (fromp)->va_size; \ (top)->va_blocksize = (fromp)->va_blocksize; \ (top)->va_atime = (fromp)->va_atime; \ (top)->va_mtime = (fromp)->va_mtime; \ (top)->va_ctime = (fromp)->va_ctime; \ (top)->va_gen = (fromp)->va_gen; \ (top)->va_flags = (fromp)->va_flags; \ (top)->va_rdev = (fromp)->va_rdev; \ (top)->va_bytes = (fromp)->va_bytes; \ (top)->va_filerev = (fromp)->va_filerev; \ } while (0) int venus_root(void *mdp, struct ucred *cred, struct proc *p, /*out*/ ViceFid *VFid) { DECL_NO_IN(coda_root); /* sets Isize & Osize */ ALLOC_NO_IN(coda_root); /* sets inp & outp */ /* send the open to venus. */ INIT_IN(inp, CODA_ROOT, cred, p); error = coda_call(mdp, Isize, &Osize, (char *)inp); if (!error) *VFid = outp->VFid; CODA_FREE(inp, coda_root_size); return error; } int venus_open(void *mdp, ViceFid *fid, int flag, struct ucred *cred, struct proc *p, /*out*/ dev_t *dev, ino_t *inode) { int cflag; DECL(coda_open); /* sets Isize & Osize */ ALLOC(coda_open); /* sets inp & outp */ /* send the open to venus. */ INIT_IN(&inp->ih, CODA_OPEN, cred, p); inp->VFid = *fid; CNV_OFLAG(cflag, flag); inp->flags = cflag; error = coda_call(mdp, Isize, &Osize, (char *)inp); if (!error) { *dev = outp->dev; *inode = outp->inode; } CODA_FREE(inp, coda_open_size); return error; } int venus_close(void *mdp, ViceFid *fid, int flag, struct ucred *cred, struct proc *p) { int cflag; DECL_NO_OUT(coda_close); /* sets Isize & Osize */ ALLOC_NO_OUT(coda_close); /* sets inp & outp */ INIT_IN(&inp->ih, CODA_CLOSE, cred, p); inp->VFid = *fid; CNV_OFLAG(cflag, flag); inp->flags = cflag; error = coda_call(mdp, Isize, &Osize, (char *)inp); CODA_FREE(inp, coda_close_size); return error; } /* * these two calls will not exist!!! the container file is read/written * directly. */ void venus_read(void) { } void venus_write(void) { } /* * this is a bit sad too. the ioctl's are for the control file, not for * normal files. */ int venus_ioctl(void *mdp, ViceFid *fid, int com, int flag, caddr_t data, struct ucred *cred, struct proc *p) { DECL(coda_ioctl); /* sets Isize & Osize */ struct PioctlData *iap = (struct PioctlData *)data; int tmp; coda_ioctl_size = VC_MAXMSGSIZE; ALLOC(coda_ioctl); /* sets inp & outp */ INIT_IN(&inp->ih, CODA_IOCTL, cred, p); inp->VFid = *fid; /* command was mutated by increasing its size field to reflect the * path and follow args. we need to subtract that out before sending * the command to venus. */ inp->cmd = (com & ~(IOCPARM_MASK << 16)); tmp = ((com >> 16) & IOCPARM_MASK) - sizeof (char *) - sizeof (int); inp->cmd |= (tmp & IOCPARM_MASK) << 16; inp->rwflag = flag; inp->len = iap->vi.in_size; inp->data = (char *)(sizeof (struct coda_ioctl_in)); error = copyin(iap->vi.in, (char*)inp + (int)inp->data, iap->vi.in_size); if (error) { CODA_FREE(inp, coda_ioctl_size); return(error); } Osize = VC_MAXMSGSIZE; error = coda_call(mdp, Isize + iap->vi.in_size, &Osize, (char *)inp); /* copy out the out buffer. */ if (!error) { if (outp->len > iap->vi.out_size) { error = EINVAL; } else { error = copyout((char *)outp + (int)outp->data, iap->vi.out, iap->vi.out_size); } } CODA_FREE(inp, coda_ioctl_size); return error; } int venus_getattr(void *mdp, ViceFid *fid, struct ucred *cred, struct proc *p, /*out*/ struct vattr *vap) { DECL(coda_getattr); /* sets Isize & Osize */ ALLOC(coda_getattr); /* sets inp & outp */ /* send the open to venus. */ INIT_IN(&inp->ih, CODA_GETATTR, cred, p); inp->VFid = *fid; error = coda_call(mdp, Isize, &Osize, (char *)inp); if (!error) { CNV_VV2V_ATTR(vap, &outp->attr); } CODA_FREE(inp, coda_getattr_size); return error; } int venus_setattr(void *mdp, ViceFid *fid, struct vattr *vap, struct ucred *cred, struct proc *p) { DECL_NO_OUT(coda_setattr); /* sets Isize & Osize */ ALLOC_NO_OUT(coda_setattr); /* sets inp & outp */ /* send the open to venus. */ INIT_IN(&inp->ih, CODA_SETATTR, cred, p); inp->VFid = *fid; CNV_V2VV_ATTR(&inp->attr, vap); error = coda_call(mdp, Isize, &Osize, (char *)inp); CODA_FREE(inp, coda_setattr_size); return error; } int venus_access(void *mdp, ViceFid *fid, int mode, struct ucred *cred, struct proc *p) { DECL_NO_OUT(coda_access); /* sets Isize & Osize */ ALLOC_NO_OUT(coda_access); /* sets inp & outp */ /* send the open to venus. */ INIT_IN(&inp->ih, CODA_ACCESS, cred, p); inp->VFid = *fid; /* NOTE: * NetBSD and Venus internals use the "data" in the low 3 bits. * Hence, the conversion. */ inp->flags = mode>>6; error = coda_call(mdp, Isize, &Osize, (char *)inp); CODA_FREE(inp, coda_access_size); return error; } int venus_readlink(void *mdp, ViceFid *fid, struct ucred *cred, struct proc *p, /*out*/ char **str, int *len) { DECL(coda_readlink); /* sets Isize & Osize */ coda_readlink_size += CODA_MAXPATHLEN; ALLOC(coda_readlink); /* sets inp & outp */ /* send the open to venus. */ INIT_IN(&inp->ih, CODA_READLINK, cred, p); inp->VFid = *fid; Osize += CODA_MAXPATHLEN; error = coda_call(mdp, Isize, &Osize, (char *)inp); if (!error) { CODA_ALLOC(*str, char *, outp->count); *len = outp->count; bcopy((char *)outp + (int)outp->data, *str, *len); } CODA_FREE(inp, coda_readlink_size); return error; } int venus_fsync(void *mdp, ViceFid *fid, struct ucred *cred, struct proc *p) { DECL_NO_OUT(coda_fsync); /* sets Isize & Osize */ ALLOC_NO_OUT(coda_fsync); /* sets inp & outp */ /* send the open to venus. */ INIT_IN(&inp->ih, CODA_FSYNC, cred, p); inp->VFid = *fid; error = coda_call(mdp, Isize, &Osize, (char *)inp); CODA_FREE(inp, coda_fsync_size); return error; } int venus_lookup(void *mdp, ViceFid *fid, const char *nm, int len, struct ucred *cred, struct proc *p, /*out*/ ViceFid *VFid, int *vtype) { DECL(coda_lookup); /* sets Isize & Osize */ coda_lookup_size += len + 1; ALLOC(coda_lookup); /* sets inp & outp */ /* send the open to venus. */ INIT_IN(&inp->ih, CODA_LOOKUP, cred, p); inp->VFid = *fid; inp->name = Isize; STRCPY(name, nm, len); /* increments Isize */ error = coda_call(mdp, Isize, &Osize, (char *)inp); if (!error) { *VFid = outp->VFid; *vtype = outp->vtype; } CODA_FREE(inp, coda_lookup_size); return error; } int venus_create(void *mdp, ViceFid *fid, const char *nm, int len, int exclusive, int mode, struct vattr *va, struct ucred *cred, struct proc *p, /*out*/ ViceFid *VFid, struct vattr *attr) { DECL(coda_create); /* sets Isize & Osize */ coda_create_size += len + 1; ALLOC(coda_create); /* sets inp & outp */ /* send the open to venus. */ INIT_IN(&inp->ih, CODA_CREATE, cred, p); inp->VFid = *fid; inp->excl = exclusive ? C_O_EXCL : 0; inp->mode = mode; CNV_V2VV_ATTR(&inp->attr, va); inp->name = Isize; STRCPY(name, nm, len); /* increments Isize */ error = coda_call(mdp, Isize, &Osize, (char *)inp); if (!error) { *VFid = outp->VFid; CNV_VV2V_ATTR(attr, &outp->attr); } CODA_FREE(inp, coda_create_size); return error; } int venus_remove(void *mdp, ViceFid *fid, const char *nm, int len, struct ucred *cred, struct proc *p) { DECL_NO_OUT(coda_remove); /* sets Isize & Osize */ coda_remove_size += len + 1; ALLOC_NO_OUT(coda_remove); /* sets inp & outp */ /* send the open to venus. */ INIT_IN(&inp->ih, CODA_REMOVE, cred, p); inp->VFid = *fid; inp->name = Isize; STRCPY(name, nm, len); /* increments Isize */ error = coda_call(mdp, Isize, &Osize, (char *)inp); CODA_FREE(inp, coda_remove_size); return error; } int venus_link(void *mdp, ViceFid *fid, ViceFid *tfid, const char *nm, int len, struct ucred *cred, struct proc *p) { DECL_NO_OUT(coda_link); /* sets Isize & Osize */ coda_link_size += len + 1; ALLOC_NO_OUT(coda_link); /* sets inp & outp */ /* send the open to venus. */ INIT_IN(&inp->ih, CODA_LINK, cred, p); inp->sourceFid = *fid; inp->destFid = *tfid; inp->tname = Isize; STRCPY(tname, nm, len); /* increments Isize */ error = coda_call(mdp, Isize, &Osize, (char *)inp); CODA_FREE(inp, coda_link_size); return error; } int venus_rename(void *mdp, ViceFid *fid, ViceFid *tfid, const char *nm, int len, const char *tnm, int tlen, struct ucred *cred, struct proc *p) { DECL_NO_OUT(coda_rename); /* sets Isize & Osize */ coda_rename_size += len + 1 + tlen + 1; ALLOC_NO_OUT(coda_rename); /* sets inp & outp */ /* send the open to venus. */ INIT_IN(&inp->ih, CODA_RENAME, cred, p); inp->sourceFid = *fid; inp->destFid = *tfid; inp->srcname = Isize; STRCPY(srcname, nm, len); /* increments Isize */ inp->destname = Isize; STRCPY(destname, tnm, tlen); /* increments Isize */ error = coda_call(mdp, Isize, &Osize, (char *)inp); CODA_FREE(inp, coda_rename_size); return error; } int venus_mkdir(void *mdp, ViceFid *fid, const char *nm, int len, struct vattr *va, struct ucred *cred, struct proc *p, /*out*/ ViceFid *VFid, struct vattr *ova) { DECL(coda_mkdir); /* sets Isize & Osize */ coda_mkdir_size += len + 1; ALLOC(coda_mkdir); /* sets inp & outp */ /* send the open to venus. */ INIT_IN(&inp->ih, CODA_MKDIR, cred, p); inp->VFid = *fid; CNV_V2VV_ATTR(&inp->attr, va); inp->name = Isize; STRCPY(name, nm, len); /* increments Isize */ error = coda_call(mdp, Isize, &Osize, (char *)inp); if (!error) { *VFid = outp->VFid; CNV_VV2V_ATTR(ova, &outp->attr); } CODA_FREE(inp, coda_mkdir_size); return error; } int venus_rmdir(void *mdp, ViceFid *fid, const char *nm, int len, struct ucred *cred, struct proc *p) { DECL_NO_OUT(coda_rmdir); /* sets Isize & Osize */ coda_rmdir_size += len + 1; ALLOC_NO_OUT(coda_rmdir); /* sets inp & outp */ /* send the open to venus. */ INIT_IN(&inp->ih, CODA_RMDIR, cred, p); inp->VFid = *fid; inp->name = Isize; STRCPY(name, nm, len); /* increments Isize */ error = coda_call(mdp, Isize, &Osize, (char *)inp); CODA_FREE(inp, coda_rmdir_size); return error; } int venus_symlink(void *mdp, ViceFid *fid, const char *lnm, int llen, const char *nm, int len, struct vattr *va, struct ucred *cred, struct proc *p) { DECL_NO_OUT(coda_symlink); /* sets Isize & Osize */ coda_symlink_size += llen + 1 + len + 1; ALLOC_NO_OUT(coda_symlink); /* sets inp & outp */ /* send the open to venus. */ INIT_IN(&inp->ih, CODA_SYMLINK, cred, p); inp->VFid = *fid; CNV_V2VV_ATTR(&inp->attr, va); inp->srcname = Isize; STRCPY(srcname, lnm, llen); /* increments Isize */ inp->tname = Isize; STRCPY(tname, nm, len); /* increments Isize */ error = coda_call(mdp, Isize, &Osize, (char *)inp); CODA_FREE(inp, coda_symlink_size); return error; } int venus_readdir(void *mdp, ViceFid *fid, int count, int offset, struct ucred *cred, struct proc *p, /*out*/ char *buffer, int *len) { DECL(coda_readdir); /* sets Isize & Osize */ coda_readdir_size = VC_MAXMSGSIZE; ALLOC(coda_readdir); /* sets inp & outp */ /* send the open to venus. */ INIT_IN(&inp->ih, CODA_READDIR, cred, p); inp->VFid = *fid; inp->count = count; inp->offset = offset; Osize = VC_MAXMSGSIZE; error = coda_call(mdp, Isize, &Osize, (char *)inp); if (!error) { bcopy((char *)outp + (int)outp->data, buffer, outp->size); *len = outp->size; } CODA_FREE(inp, coda_readdir_size); return error; } int venus_fhtovp(void *mdp, ViceFid *fid, struct ucred *cred, struct proc *p, /*out*/ ViceFid *VFid, int *vtype) { DECL(coda_vget); /* sets Isize & Osize */ ALLOC(coda_vget); /* sets inp & outp */ /* Send the open to Venus. */ INIT_IN(&inp->ih, CODA_VGET, cred, p); inp->VFid = *fid; error = coda_call(mdp, Isize, &Osize, (char *)inp); if (!error) { *VFid = outp->VFid; *vtype = outp->vtype; } CODA_FREE(inp, coda_vget_size); return error; }