From a085510ad54971419be613ad0bec378edbc05bf0 Mon Sep 17 00:00:00 2001 From: rvb Date: Sat, 29 Aug 1998 21:14:52 +0000 Subject: Very Preliminary Coda --- sys/fs/coda/README | 60 + sys/fs/coda/TODO | 12 + sys/fs/coda/cnode.h | 343 ++++++ sys/fs/coda/coda.h | 677 ++++++++++ sys/fs/coda/coda_fbsd.c | 241 ++++ sys/fs/coda/coda_io.h | 125 ++ sys/fs/coda/coda_kernel.h | 64 + sys/fs/coda/coda_namecache.c | 898 ++++++++++++++ sys/fs/coda/coda_namecache.h | 273 ++++ sys/fs/coda/coda_opstats.h | 129 ++ sys/fs/coda/coda_pioctl.h | 124 ++ sys/fs/coda/coda_psdev.c | 756 ++++++++++++ sys/fs/coda/coda_subr.c | 750 +++++++++++ sys/fs/coda/coda_subr.h | 45 + sys/fs/coda/coda_venus.c | 654 ++++++++++ sys/fs/coda/coda_venus.h | 131 ++ sys/fs/coda/coda_vfsops.c | 887 +++++++++++++ sys/fs/coda/coda_vfsops.h | 78 ++ sys/fs/coda/coda_vnops.c | 2802 ++++++++++++++++++++++++++++++++++++++++++ sys/fs/coda/coda_vnops.h | 138 +++ 20 files changed, 9187 insertions(+) create mode 100644 sys/fs/coda/README create mode 100644 sys/fs/coda/TODO create mode 100644 sys/fs/coda/cnode.h create mode 100644 sys/fs/coda/coda.h create mode 100644 sys/fs/coda/coda_fbsd.c create mode 100644 sys/fs/coda/coda_io.h create mode 100644 sys/fs/coda/coda_kernel.h create mode 100644 sys/fs/coda/coda_namecache.c create mode 100644 sys/fs/coda/coda_namecache.h create mode 100644 sys/fs/coda/coda_opstats.h create mode 100644 sys/fs/coda/coda_pioctl.h create mode 100644 sys/fs/coda/coda_psdev.c create mode 100644 sys/fs/coda/coda_subr.c create mode 100644 sys/fs/coda/coda_subr.h create mode 100644 sys/fs/coda/coda_venus.c create mode 100644 sys/fs/coda/coda_venus.h create mode 100644 sys/fs/coda/coda_vfsops.c create mode 100644 sys/fs/coda/coda_vfsops.h create mode 100644 sys/fs/coda/coda_vnops.c create mode 100644 sys/fs/coda/coda_vnops.h (limited to 'sys') diff --git a/sys/fs/coda/README b/sys/fs/coda/README new file mode 100644 index 0000000..49ccad6 --- /dev/null +++ b/sys/fs/coda/README @@ -0,0 +1,60 @@ + Announcing the Availability of the + Coda Distributed + Filesystem + for + BSD Unix Systems + + Coda is a distributed file system like NFS and AFS. It is +freely available, like NFS. But it functions much like AFS in being a +"stateful" file system. Coda and AFS cache files on your local +machine to improve performance. But Coda goes a step further than AFS +by letting you access the cached files when there is no available +network, viz. disconnected laptops and network outages. In Coda, both +the client and server are outside the kernel which makes them easier +to experiment with. + +To get more information on Coda, I would like to refer people to + http://www.coda.cs.cmu.edu +There is a wealth of documents, papers, theses there. There is also a +good introduction to the Coda File System in + http://www.coda.cs.cmu.edu/ljpaper/lj.html + +Coda was originally developed as an academic prototype/testbed. It is +being polished and rewritten where necessary. Coda is a work in +progress and does have bugs. It is, though, very usable. Our +interest is in making Coda available to as many people as possible and +to have Coda evolve and flourish. + +The bulk of the Coda file system code supports the Coda client +program, the Coda server program and the utilities needed by both. +All these programs are unix programs and can run equally well on any +Unix platform. Our main development thrust is improving these +programs. There is a small part of Coda that deals with the kernel to +file system interface. This code is OS specific (but should not be +platform specific). + +Coda is currently available for several OS's and platforms: + Freebsd-2.2.5: i386 + Freebsd-2.2.6: i386 + Freebsd -current: i386 + linux 2.0: i386 & sparc + linux 2.1: i386 & sparc + NetBSD 1.3: i386 + NetBSD -current: i386 +The relevant sources, binaries, and docs can be found in + ftp://ftp.coda.cs.cmu.edu/pub/coda/ + +We intend to come out with new Coda releases often, not daily. We +don't wish to slight any OS/platform not mentioned above. We are just +limited in our resources as to what we can support internally. We +will be happy to integrate OpenBSD support as well as other OS +support. Also, adding platform support is relatively easy and we can +discuss this. The only problem is that Coda has a light weight +process package. It does some manipulations in assembler which would +have to be redone for a different platform. + +There are several mailing lists @coda.cs.cmu.edu that discuss coda: +coda-announce and linux-coda. We are going to revise linux-coda to be +OS neutral, since it is mainly Coda we want to discuss. We appreciate +comments, feedback, bug reports, bug fixes, enhancements, etc. + diff --git a/sys/fs/coda/TODO b/sys/fs/coda/TODO new file mode 100644 index 0000000..f19b4b6 --- /dev/null +++ b/sys/fs/coda/TODO @@ -0,0 +1,12 @@ +Near term: + Existing VOP_LOCKS's should proabably be + vn_lock since that is what they were in -stable. + Fix bug in executing/mapping new files. + +Medium term: + Add missing VFS methods. + Do performance profile. + Tune hash algorithm used in cfs_namecache. + +Eventually: + Use standard queue macros. diff --git a/sys/fs/coda/cnode.h b/sys/fs/coda/cnode.h new file mode 100644 index 0000000..901dc8a --- /dev/null +++ b/sys/fs/coda/cnode.h @@ -0,0 +1,343 @@ +/* + + 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. +*/ + +/* $Header: /afs/cs/project/coda-src/cvs/coda/kernel-src/vfs/freebsd/cfs/cnode.h,v 1.10 1998/08/28 18:12:25 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: cnode.h,v $ + * Revision 1.10 1998/08/28 18:12:25 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.9 1998/08/18 17:05:24 rvb + * Don't use __RCSID now + * + * Revision 1.8 1998/08/18 16:31:49 rvb + * Sync the code for NetBSD -current; test on 1.3 later + * + * Revision 1.7 98/02/24 22:22:53 rvb + * Fixes up mainly to flush iopen and friends + * + * Revision 1.6 98/01/31 20:53:19 rvb + * First version that works on FreeBSD 2.2.5 + * + * Revision 1.5 98/01/23 11:53:51 rvb + * Bring RVB_CFS1_1 to HEAD + * + * Revision 1.4.2.5 98/01/23 11:21:14 rvb + * Sync with 2.2.5 + * + * Revision 1.4.2.4 98/01/22 13:03:38 rvb + * Had Breaken ls . + * + * Revision 1.4.2.3 97/12/19 14:26:09 rvb + * session id + * + * Revision 1.4.2.2 97/12/16 12:40:24 rvb + * Sync with 1.3 + * + * Revision 1.4.2.1 97/12/06 17:41:28 rvb + * Sync with peters coda.h + * + * Revision 1.4 97/12/05 10:39:30 rvb + * Read CHANGES + * + * Revision 1.3.18.2 97/11/12 12:09:45 rvb + * reorg pass1 + * + * Revision 1.3.18.1 97/10/29 16:06:31 rvb + * Kill DYING + * + * Revision 1.3 1996/12/12 22:11:03 bnoble + * Fixed the "downcall invokes venus operation" deadlock in all known cases. + * There may be more. + * + * Revision 1.2 1996/01/02 16:57:26 bnoble + * Added support for Coda MiniCache and raw inode calls (final commit) + * + * Revision 1.1.2.1 1995/12/20 01:57:53 bnoble + * Added CFS-specific files + * + * Revision 3.1.1.1 1995/03/04 19:08:23 bnoble + * Branch for NetBSD port revisions + * + * Revision 3.1 1995/03/04 19:08:23 bnoble + * Bump to major revision 3 to prepare for NetBSD port + * + * Revision 2.2 1994/12/06 13:39:18 dcs + * Add a flag value to indicate a cnode was orphaned, e.g. the venus + * that created it has exited. This will allow one to restart venus + * even though some process may be cd'd into /coda. + * + * Revision 2.1 94/07/21 16:25:33 satya + * Conversion to C++ 3.0; start of Coda Release 2.0 + * + * Revision 1.2.7.1 94/06/16 11:26:02 raiff + * Branch for release beta-16Jun1994_39118 + * + * Revision 1.2 92/10/27 17:58:41 lily + * merge kernel/latest and alpha/src/cfs + * + * Revision 2.3 92/09/30 14:16:53 mja + * Picked up fixed #ifdef _KERNEL. 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:27:24 mrt + * Created for the Coda File System. + * [90/05/23 dcs] + * + * Revision 1.4 90/05/31 17:02:16 dcs + * Prepare for merge with facilities kernel. + * + * + * + */ + +#ifndef _CNODE_H_ +#define _CNODE_H_ + +#include + +#ifdef __FreeBSD__ + +/* for the prototype of DELAY() */ +#include + +#ifdef __FreeBSD_version +/* You would think that or something would include this */ +#include + +MALLOC_DECLARE(M_CFS); + +#else + +/* yuck yuck yuck */ +#define vref(x) cvref(x) +extern void cvref(struct vnode *vp); +/* yuck yuck yuck */ + +#endif +#endif + +#if defined(__NetBSD__) && defined(NetBSD1_3) && (NetBSD1_3 >= 7) +#define NEW_LOCKMGR(l, f, i) lockmgr(l, f, i) +#define VOP_X_LOCK(vn, fl) vn_lock(vn, fl) +#define VOP_X_UNLOCK(vn, fl) VOP_UNLOCK(vn, fl) + +#elif defined(__FreeBSD_version) +#define NEW_LOCKMGR(l, f, i) lockmgr(l, f, i, curproc) +#define VOP_X_LOCK(vn, fl) vn_lock(vn, fl, curproc) +#define VOP_X_UNLOCK(vn, fl) VOP_UNLOCK(vn, fl, curproc) + +/* NetBSD 1.3 & FreeBSD 2.2.x */ +#else +#undef NEW_LOCKMGR +#define VOP_X_LOCK(vn, fl) VOP_LOCK(vn) +#define VOP_X_UNLOCK(vn, fl) VOP_UNLOCK(vn) +#endif + +/* + * tmp below since we need struct queue + */ +#include + +/* + * Cnode lookup stuff. + * NOTE: CFS_CACHESIZE must be a power of 2 for cfshash to work! + */ +#define CFS_CACHESIZE 512 + +#define CFS_ALLOC(ptr, cast, size) \ +do { \ + ptr = (cast)malloc((unsigned long) size, M_CFS, M_WAITOK); \ + if (ptr == 0) { \ + panic("kernel malloc returns 0 at %s:%d\n", __FILE__, __LINE__); \ + } \ +} while (0) + +#define CFS_FREE(ptr, size) free((ptr), M_CFS) + +/* + * global cache state control + */ +extern int cfsnc_use; + +/* + * Used to select debugging statements throughout the cfs code. + */ +extern int cfsdebug; +extern int cfsnc_debug; +extern int cfs_printf_delay; +extern int cfs_vnop_print_entry; +extern int cfs_psdev_print_entry; +extern int cfs_vfsop_print_entry; + +#define CFSDBGMSK(N) (1 << N) +#define CFSDEBUG(N, STMT) { if (cfsdebug & CFSDBGMSK(N)) { STMT } } +#define myprintf(args) \ +do { \ + if (cfs_printf_delay) \ + DELAY(cfs_printf_delay);\ + printf args ; \ +} while (0) + +struct cnode { + struct vnode *c_vnode; + u_short c_flags; /* flags (see below) */ + ViceFid c_fid; /* file handle */ +#ifdef NEW_LOCKMGR + struct lock c_lock; /* new lock protocol */ +#endif + struct vnode *c_ovp; /* open vnode pointer */ + u_short c_ocount; /* count of openers */ + u_short c_owrite; /* count of open for write */ + struct vattr c_vattr; /* attributes */ + char *c_symlink; /* pointer to symbolic link */ + u_short c_symlen; /* length of symbolic link */ + dev_t c_device; /* associated vnode device */ + ino_t c_inode; /* associated vnode inode */ + struct cnode *c_next; /* links if on NetBSD machine */ +}; +#define VTOC(vp) ((struct cnode *)(vp)->v_data) +#define CTOV(cp) ((struct vnode *)((cp)->c_vnode)) + +/* flags */ +#define C_VATTR 0x01 /* Validity of vattr in the cnode */ +#define C_SYMLINK 0x02 /* Validity of symlink pointer in the Code */ +#define C_WANTED 0x08 /* Set if lock wanted */ +#define C_LOCKED 0x10 /* Set if lock held */ +#define C_UNMOUNTING 0X20 /* Set if unmounting */ +#define C_PURGING 0x40 /* Set if purging a fid */ + +#define VALID_VATTR(cp) ((cp->c_flags) & C_VATTR) +#define VALID_SYMLINK(cp) ((cp->c_flags) & C_SYMLINK) +#define IS_UNMOUNTING(cp) ((cp)->c_flags & C_UNMOUNTING) + +struct vcomm { + u_long vc_seq; + struct selinfo vc_selproc; + struct queue vc_requests; + struct queue vc_replys; +}; + +#define VC_OPEN(vcp) ((vcp)->vc_requests.forw != NULL) +#define MARK_VC_CLOSED(vcp) (vcp)->vc_requests.forw = NULL; +#define MARK_VC_OPEN(vcp) /* MT */ + +struct cfs_clstat { + int ncalls; /* client requests */ + int nbadcalls; /* upcall failures */ + int reqs[CFS_NCALLS]; /* count of each request */ +}; +extern struct cfs_clstat cfs_clstat; + +/* + * CFS structure to hold mount/file system information + */ +struct cfs_mntinfo { + struct vnode *mi_rootvp; + struct mount *mi_vfsp; + struct vcomm mi_vcomm; +}; +extern struct cfs_mntinfo cfs_mnttbl[]; /* indexed by minor device number */ + +/* + * vfs pointer to mount info + */ +#define vftomi(vfsp) ((struct cfs_mntinfo *)(vfsp->mnt_data)) +#define CFS_MOUNTED(vfsp) (vftomi((vfsp)) != (struct cfs_mntinfo *)0) + +/* + * vnode pointer to mount info + */ +#define vtomi(vp) ((struct cfs_mntinfo *)(vp->v_mount->mnt_data)) + +/* + * Used for identifying usage of "Control" object + */ +extern struct vnode *cfs_ctlvp; +#define IS_CTL_VP(vp) ((vp) == cfs_ctlvp) +#define IS_CTL_NAME(vp, name, l)((l == CFS_CONTROLLEN) \ + && ((vp) == vtomi((vp))->mi_rootvp) \ + && strncmp(name, CFS_CONTROL, l) == 0) + +/* + * An enum to tell us whether something that will remove a reference + * to a cnode was a downcall or not + */ +enum dc_status { + IS_DOWNCALL = 6, + NOT_DOWNCALL = 7 +}; + +/* cfs_psdev.h */ +int cfscall(struct cfs_mntinfo *mntinfo, int inSize, int *outSize, caddr_t buffer); + +/* cfs_subr.h */ +int handleDownCall(int opcode, union outputArgs *out); +void cfs_unmounting(struct mount *whoIam); +int cfs_vmflush(struct cnode *cp); + +/* cfs_vnodeops.h */ +struct cnode *makecfsnode(ViceFid *fid, struct mount *vfsp, short type); +int cfs_vnodeopstats_init(void); + +/* cfs_vfsops.h */ +struct mount *devtomp(dev_t dev); + +#if !(defined NetBSD1_3) && !defined(__FreeBSD_version) +#define __RCSID(x) static char *rcsid = x +#endif + +/* sigh */ +#define CFS_RDWR ((u_long) 31) + +#endif /* _CNODE_H_ */ + diff --git a/sys/fs/coda/coda.h b/sys/fs/coda/coda.h new file mode 100644 index 0000000..78de1fd --- /dev/null +++ b/sys/fs/coda/coda.h @@ -0,0 +1,677 @@ +/* + + 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. +*/ + +/* $Header: /afs/cs/project/coda-src/cvs/coda/kernel-src/vfs/freebsd/cfs/coda.h,v 1.10 1998/08/28 18:12:26 rvb Exp $ */ + +/* + * + * Based on cfs.h from Mach, but revamped for increased simplicity. + * Linux modifications by Peter Braam, Aug 1996 + */ + +#ifndef _CFS_HEADER_ +#define _CFS_HEADER_ + + + +/* Catch new _KERNEL defn for NetBSD */ +#ifdef __NetBSD__ +#include +#endif + +#if defined(__linux__) || defined(__CYGWIN32__) +#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 +#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 + + +/* + * Cfs constants + */ +#define CFS_MAXNAMLEN 255 +#define CFS_MAXPATHLEN 1024 +#define CFS_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 + +/* 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_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[CFS_MAXNAMLEN + 1];/* name must be no longer than this */ +}; +#undef DIRSIZ +#define DIRSIZ(dp) ((sizeof (struct venus_dirent) - (CFS_MAXNAMLEN+1)) + \ + (((dp)->d_namlen+1 + 3) &~ 3)) + +/* + * File types + */ +#define CDT_UNKNOWN 0 +#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_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) +{ + if ( fid ) { + return (fid->Unique + (fid->Vnode << 10) + (fid->Volume << 20)); + } else { + return 0; + } +} +#endif + +#ifndef _VUID_T_ +#define _VUID_T_ +typedef u_long vuid_t; +typedef u_long 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 +}; +#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) */ + 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 CFS_ROOT ((u_long) 2) +#define CFS_SYNC ((u_long) 3) +#define CFS_OPEN ((u_long) 4) +#define CFS_CLOSE ((u_long) 5) +#define CFS_IOCTL ((u_long) 6) +#define CFS_GETATTR ((u_long) 7) +#define CFS_SETATTR ((u_long) 8) +#define CFS_ACCESS ((u_long) 9) +#define CFS_LOOKUP ((u_long) 10) +#define CFS_CREATE ((u_long) 11) +#define CFS_REMOVE ((u_long) 12) +#define CFS_LINK ((u_long) 13) +#define CFS_RENAME ((u_long) 14) +#define CFS_MKDIR ((u_long) 15) +#define CFS_RMDIR ((u_long) 16) +#define CFS_READDIR ((u_long) 17) +#define CFS_SYMLINK ((u_long) 18) +#define CFS_READLINK ((u_long) 19) +#define CFS_FSYNC ((u_long) 20) +#define CFS_INACTIVE ((u_long) 21) +#define CFS_VGET ((u_long) 22) +#define CFS_SIGNAL ((u_long) 23) +#define CFS_REPLACE ((u_long) 24) +#define CFS_FLUSH ((u_long) 25) +#define CFS_PURGEUSER ((u_long) 26) +#define CFS_ZAPFILE ((u_long) 27) +#define CFS_ZAPDIR ((u_long) 28) +#define CFS_ZAPVNODE ((u_long) 29) +#define CFS_PURGEFID ((u_long) 30) +#define CFS_NCALLS 31 + +#define DOWNCALL(opcode) (opcode >= CFS_REPLACE && opcode <= CFS_PURGEFID) + +#define VC_MAXDATASIZE 8192 +#define VC_MAXMSGSIZE sizeof(union inputArgs)+sizeof(union outputArgs) +\ + VC_MAXDATASIZE + + + +/* + * Venus <-> Coda RPC arguments + */ +struct cfs_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 cfs_out_hdr { + unsigned long opcode; + unsigned long unique; + unsigned long result; +}; + +/* cfs_root: NO_IN */ +struct cfs_root_out { + struct cfs_out_hdr oh; + ViceFid VFid; +}; + +struct cfs_root_in { + struct cfs_in_hdr in; +}; + +/* cfs_sync: */ +/* Nothing needed for cfs_sync */ + +/* cfs_open: */ +struct cfs_open_in { + struct cfs_in_hdr ih; + ViceFid VFid; + int flags; +}; + +struct cfs_open_out { + struct cfs_out_hdr oh; + cdev_t dev; + ino_t inode; +}; + + +/* cfs_close: */ +struct cfs_close_in { + struct cfs_in_hdr ih; + ViceFid VFid; + int flags; +}; + +struct cfs_close_out { + struct cfs_out_hdr out; +}; + +/* cfs_ioctl: */ +struct cfs_ioctl_in { + struct cfs_in_hdr ih; + ViceFid VFid; + int cmd; + int len; + int rwflag; + char *data; /* Place holder for data. */ +}; + +struct cfs_ioctl_out { + struct cfs_out_hdr oh; + int len; + caddr_t data; /* Place holder for data. */ +}; + + +/* cfs_getattr: */ +struct cfs_getattr_in { + struct cfs_in_hdr ih; + ViceFid VFid; +}; + +struct cfs_getattr_out { + struct cfs_out_hdr oh; + struct coda_vattr attr; +}; + + +/* cfs_setattr: NO_OUT */ +struct cfs_setattr_in { + struct cfs_in_hdr ih; + ViceFid VFid; + struct coda_vattr attr; +}; + +struct cfs_setattr_out { + struct cfs_out_hdr out; +}; + +/* cfs_access: NO_OUT */ +struct cfs_access_in { + struct cfs_in_hdr ih; + ViceFid VFid; + int flags; +}; + +struct cfs_access_out { + struct cfs_out_hdr out; +}; + +/* cfs_lookup: */ +struct cfs_lookup_in { + struct cfs_in_hdr ih; + ViceFid VFid; + int name; /* Place holder for data. */ +}; + +struct cfs_lookup_out { + struct cfs_out_hdr oh; + ViceFid VFid; + int vtype; +}; + + +/* cfs_create: */ +struct cfs_create_in { + struct cfs_in_hdr ih; + ViceFid VFid; + struct coda_vattr attr; + int excl; + int mode; + int name; /* Place holder for data. */ +}; + +struct cfs_create_out { + struct cfs_out_hdr oh; + ViceFid VFid; + struct coda_vattr attr; +}; + + +/* cfs_remove: NO_OUT */ +struct cfs_remove_in { + struct cfs_in_hdr ih; + ViceFid VFid; + int name; /* Place holder for data. */ +}; + +struct cfs_remove_out { + struct cfs_out_hdr out; +}; + +/* cfs_link: NO_OUT */ +struct cfs_link_in { + struct cfs_in_hdr ih; + ViceFid sourceFid; /* cnode to link *to* */ + ViceFid destFid; /* Directory in which to place link */ + int tname; /* Place holder for data. */ +}; + +struct cfs_link_out { + struct cfs_out_hdr out; +}; + + +/* cfs_rename: NO_OUT */ +struct cfs_rename_in { + struct cfs_in_hdr ih; + ViceFid sourceFid; + int srcname; + ViceFid destFid; + int destname; +}; + +struct cfs_rename_out { + struct cfs_out_hdr out; +}; + +/* cfs_mkdir: */ +struct cfs_mkdir_in { + struct cfs_in_hdr ih; + ViceFid VFid; + struct coda_vattr attr; + int name; /* Place holder for data. */ +}; + +struct cfs_mkdir_out { + struct cfs_out_hdr oh; + ViceFid VFid; + struct coda_vattr attr; +}; + + +/* cfs_rmdir: NO_OUT */ +struct cfs_rmdir_in { + struct cfs_in_hdr ih; + ViceFid VFid; + int name; /* Place holder for data. */ +}; + +struct cfs_rmdir_out { + struct cfs_out_hdr out; +}; + +/* cfs_readdir: */ +struct cfs_readdir_in { + struct cfs_in_hdr ih; + ViceFid VFid; + int count; + int offset; +}; + +struct cfs_readdir_out { + struct cfs_out_hdr oh; + int size; + caddr_t data; /* Place holder for data. */ +}; + +/* cfs_symlink: NO_OUT */ +struct cfs_symlink_in { + struct cfs_in_hdr ih; + ViceFid VFid; /* Directory to put symlink in */ + int srcname; + struct coda_vattr attr; + int tname; +}; + +struct cfs_symlink_out { + struct cfs_out_hdr out; +}; + +/* cfs_readlink: */ +struct cfs_readlink_in { + struct cfs_in_hdr ih; + ViceFid VFid; +}; + +struct cfs_readlink_out { + struct cfs_out_hdr oh; + int count; + caddr_t data; /* Place holder for data. */ +}; + + +/* cfs_fsync: NO_OUT */ +struct cfs_fsync_in { + struct cfs_in_hdr ih; + ViceFid VFid; +}; + +struct cfs_fsync_out { + struct cfs_out_hdr out; +}; + +/* cfs_inactive: NO_OUT */ +struct cfs_inactive_in { + struct cfs_in_hdr ih; + ViceFid VFid; +}; + +/* cfs_vget: */ +struct cfs_vget_in { + struct cfs_in_hdr ih; + ViceFid VFid; +}; + +struct cfs_vget_out { + struct cfs_out_hdr oh; + ViceFid VFid; + int vtype; +}; + + +/* CFS_SIGNAL is out-of-band, doesn't need data. */ +/* CFS_INVALIDATE is a venus->kernel call */ +/* CFS_FLUSH is a venus->kernel call */ + +/* cfs_purgeuser: */ +/* CFS_PURGEUSER is a venus->kernel call */ +struct cfs_purgeuser_out { + struct cfs_out_hdr oh; + struct coda_cred cred; +}; + +/* cfs_zapfile: */ +/* CFS_ZAPFILE is a venus->kernel call */ +struct cfs_zapfile_out { + struct cfs_out_hdr oh; + ViceFid CodaFid; +}; + +/* cfs_zapdir: */ +/* CFS_ZAPDIR is a venus->kernel call */ +struct cfs_zapdir_out { + struct cfs_out_hdr oh; + ViceFid CodaFid; +}; + +/* cfs_zapnode: */ +/* CFS_ZAPVNODE is a venus->kernel call */ +struct cfs_zapvnode_out { + struct cfs_out_hdr oh; + struct coda_cred cred; + ViceFid VFid; +}; + +/* cfs_purgefid: */ +/* CFS_PURGEFID is a venus->kernel call */ +struct cfs_purgefid_out { + struct cfs_out_hdr oh; + ViceFid CodaFid; +}; + +/* cfs_rdwr: */ +struct cfs_rdwr_in { + struct cfs_in_hdr ih; + ViceFid VFid; + int rwflag; + int count; + int offset; + int ioflag; + caddr_t data; /* Place holder for data. */ +}; + +struct cfs_rdwr_out { + struct cfs_out_hdr oh; + int rwflag; + int count; + caddr_t data; /* Place holder for data. */ +}; + + +/* cfs_replace: */ +/* CFS_REPLACE is a venus->kernel call */ +struct cfs_replace_out { /* cfs_replace is a venus->kernel call */ + struct cfs_out_hdr oh; + ViceFid NewFid; + ViceFid OldFid; +}; + +/* + * Occasionally, don't cache the fid returned by CFS_LOOKUP. For instance, if + * the fid is inconsistent. This case is handled by setting the top bit of the + * return result parameter. + */ +#define CFS_NOCACHE 0x80000000 + +union inputArgs { + struct cfs_in_hdr ih; /* NB: every struct below begins with an ih */ + struct cfs_open_in cfs_open; + struct cfs_close_in cfs_close; + struct cfs_ioctl_in cfs_ioctl; + struct cfs_getattr_in cfs_getattr; + struct cfs_setattr_in cfs_setattr; + struct cfs_access_in cfs_access; + struct cfs_lookup_in cfs_lookup; + struct cfs_create_in cfs_create; + struct cfs_remove_in cfs_remove; + struct cfs_link_in cfs_link; + struct cfs_rename_in cfs_rename; + struct cfs_mkdir_in cfs_mkdir; + struct cfs_rmdir_in cfs_rmdir; + struct cfs_readdir_in cfs_readdir; + struct cfs_symlink_in cfs_symlink; + struct cfs_readlink_in cfs_readlink; + struct cfs_fsync_in cfs_fsync; + struct cfs_inactive_in cfs_inactive; + struct cfs_vget_in cfs_vget; + struct cfs_rdwr_in cfs_rdwr; +}; + +union outputArgs { + struct cfs_out_hdr oh; /* NB: every struct below begins with an oh */ + struct cfs_root_out cfs_root; + struct cfs_open_out cfs_open; + struct cfs_ioctl_out cfs_ioctl; + struct cfs_getattr_out cfs_getattr; + struct cfs_lookup_out cfs_lookup; + struct cfs_create_out cfs_create; + struct cfs_mkdir_out cfs_mkdir; + struct cfs_readdir_out cfs_readdir; + struct cfs_readlink_out cfs_readlink; + struct cfs_vget_out cfs_vget; + struct cfs_purgeuser_out cfs_purgeuser; + struct cfs_zapfile_out cfs_zapfile; + struct cfs_zapdir_out cfs_zapdir; + struct cfs_zapvnode_out cfs_zapvnode; + struct cfs_purgefid_out cfs_purgefid; + struct cfs_rdwr_out cfs_rdwr; + struct cfs_replace_out cfs_replace; +}; + +union cfs_downcalls { + /* CFS_INVALIDATE is a venus->kernel call */ + /* CFS_FLUSH is a venus->kernel call */ + struct cfs_purgeuser_out purgeuser; + struct cfs_zapfile_out zapfile; + struct cfs_zapdir_out zapdir; + struct cfs_zapvnode_out zapvnode; + struct cfs_purgefid_out purgefid; + struct cfs_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 CFS_CONTROL ".CONTROL" +#define CFS_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 + diff --git a/sys/fs/coda/coda_fbsd.c b/sys/fs/coda/coda_fbsd.c new file mode 100644 index 0000000..23d55cc --- /dev/null +++ b/sys/fs/coda/coda_fbsd.c @@ -0,0 +1,241 @@ +/* + + 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. +*/ + +/* $Header: /afs/cs/project/coda-src/cvs/coda/kernel-src/vfs/freebsd/cfs/cfs_fbsd.c,v 1.6 1998/08/28 18:12:11 rvb Exp $ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef DEVFS +#include +#endif +#include + +#include +#include +#include +#include + +/* + From: "Jordan K. Hubbard" + Subject: Re: New 3.0 SNAPshot CDROM about ready for production.. + To: "Robert.V.Baron" + Date: Fri, 20 Feb 1998 15:57:01 -0800 + + > Also I need a character device major number. (and might want to reserve + > a block of 10 syscalls.) + + Just one char device number? No block devices? Very well, cdev 93 is yours! +*/ + +#define VC_DEV_NO 93 + +#ifdef __FreeBSD_version +/* Type of device methods. */ +extern d_open_t vc_nb_open; +extern d_close_t vc_nb_close; +extern d_read_t vc_nb_read; +extern d_write_t vc_nb_write; +extern d_ioctl_t vc_nb_ioctl; +extern d_poll_t vc_nb_poll; + +static struct cdevsw vccdevsw = +{ + vc_nb_open, vc_nb_close, vc_nb_read, vc_nb_write, /*93*/ + vc_nb_ioctl, nostop, nullreset, nodevtotty, + vc_nb_poll, nommap, NULL, "Coda", NULL, -1 }; +#else +/* Type of device methods. */ +#define D_OPEN_T d_open_t +#define D_CLOSE_T d_close_t +#define D_RDWR_T d_rdwr_t +#define D_READ_T d_read_t +#define D_WRITE_T d_write_t +#define D_IOCTL_T d_ioctl_t +#define D_SELECT_T d_select_t + +/* rvb why */ +D_OPEN_T vc_nb_open; /* was is defined in cfs_FreeBSD.h */ +D_CLOSE_T vc_nb_close; +D_READ_T vc_nb_read; +D_WRITE_T vc_nb_write; +D_IOCTL_T vc_nb_ioctl; +D_SELECT_T vc_nb_select; + +static struct cdevsw vccdevsw = +{ + vc_nb_open, vc_nb_close, vc_nb_read, vc_nb_write, + vc_nb_ioctl, nostop, nullreset, nodevtotty, + vc_nb_select, nommap, NULL, "Coda", NULL, -1 }; + +PSEUDO_SET(vcattach, vc); +#endif + +void vcattach __P((void)); +static dev_t vccdev; + +int vcdebug = 1; +#define VCDEBUG if (vcdebug) printf + +void +vcattach(void) +{ + /* + * In case we are an LKM, set up device switch. + */ + if (0 == (vccdev = makedev(VC_DEV_NO, 0))) + VCDEBUG("makedev returned null\n"); + else + VCDEBUG("makedev OK.\n"); + + cdevsw_add(&vccdev, &vccdevsw, NULL); + VCDEBUG("cfs: vccdevsw entry installed at %d.\n", major(vccdev)); +} + +void +cvref(vp) + struct vnode *vp; +{ + if (vp->v_usecount <= 0) + panic("vref used where vget required"); + + vp->v_usecount++; +} + + +#ifdef __FreeBSD_version +static vc_devsw_installed = 0; + +static void vc_drvinit __P((void *unused)); +static void +vc_drvinit(void *unused) +{ + dev_t dev; + + if( ! vc_devsw_installed ) { + dev = makedev(VC_DEV_NO, 0); + cdevsw_add(&dev,&vccdevsw, NULL); + vc_devsw_installed = 1; + } +} + +int +cfs_fbsd_getpages(v) + void *v; +{ + struct vop_getpages_args *ap = v; + struct vnode *vp = ap->a_vp; + struct cnode *cp = VTOC(vp); + int ret = 0; + +#if 1 + /*??? a_offset */ + ret = vnode_pager_generic_getpages(ap->a_vp, ap->a_m, ap->a_count, + ap->a_reqpage); + return ret; +#else + { + struct vnode *vp = ap->a_vp; + struct cnode *cp = VTOC(vp); + struct vnode *cfvp = cp->c_ovp; + int opened_internally = 0; + struct ucred *cred = (struct ucred *) 0; + struct proc *p = curproc; + int error = 0; + + if (IS_CTL_VP(vp)) { + return(EINVAL); + } + + /* Redirect the request to UFS. */ + + if (cfvp == NULL) { + opened_internally = 1; + + error = VOP_OPEN(vp, FREAD, cred, p); +printf("cfs_getp: Internally Opening %p\n", vp); + + if (error) { + printf("cfs_getpage: VOP_OPEN on container failed %d\n", error); + return (error); + } + if (vp->v_type == VREG) { + error = vfs_object_create(vp, p, cred, 1); + if (error != 0) { + printf("cfs_getpage: vfs_object_create() returns %d\n", error); + vput(vp); + return(error); + } + } + + cfvp = cp->c_ovp; + } else { +printf("cfs_getp: has container %p\n", cfvp); + } + +printf("cfs_fbsd_getpages: using container "); +/* + error = vnode_pager_generic_getpages(cfvp, ap->a_m, ap->a_count, + ap->a_reqpage); +*/ + error = VOP_GETPAGES(cfvp, ap->a_m, ap->a_count, + ap->a_reqpage, ap->a_offset); +printf("error = %d\n", error); + + /* Do an internal close if necessary. */ + if (opened_internally) { + (void)VOP_CLOSE(vp, FREAD, cred, p); + } + + return(error); + } +#endif +} + +int +cfs_fbsd_putpages(v) + void *v; +{ + struct vop_putpages_args *ap = v; + + /*??? a_offset */ + return vnode_pager_generic_putpages(ap->a_vp, ap->a_m, ap->a_count, + ap->a_sync, ap->a_rtvals); +} + + +SYSINIT(vccdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+VC_DEV_NO,vc_drvinit,NULL) +#endif diff --git a/sys/fs/coda/coda_io.h b/sys/fs/coda/coda_io.h new file mode 100644 index 0000000..e515594 --- /dev/null +++ b/sys/fs/coda/coda_io.h @@ -0,0 +1,125 @@ +/* + + 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. +*/ + +/* $Header: /afs/cs/project/coda-src/cvs/coda/kernel-src/vfs/freebsd/cfs/cfsio.h,v 1.5 1998/08/18 17:05:23 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: cfsio.h,v $ + * Revision 1.5 1998/08/18 17:05:23 rvb + * Don't use __RCSID now + * + * Revision 1.4 1998/08/18 16:31:47 rvb + * Sync the code for NetBSD -current; test on 1.3 later + * + * Revision 1.3 98/01/23 11:53:49 rvb + * Bring RVB_CFS1_1 to HEAD + * + * Revision 1.2.38.1 97/12/16 12:40:22 rvb + * Sync with 1.3 + * + * Revision 1.2 96/01/02 16:57:15 bnoble + * Added support for Coda MiniCache and raw inode calls (final commit) + * + * Revision 1.1.2.1 1995/12/20 01:57:42 bnoble + * Added CFS-specific files + * + * Revision 3.1.1.1 1995/03/04 19:08:20 bnoble + * Branch for NetBSD port revisions + * + * Revision 3.1 1995/03/04 19:08:20 bnoble + * Bump to major revision 3 to prepare for NetBSD port + * + * Revision 2.1 1994/07/21 16:25:25 satya + * Conversion to C++ 3.0; start of Coda Release 2.0 + * + * Revision 1.3 94/06/14 16:53:47 dcs + * Added support for ODY-like mounting in the kernel (SETS) + * + * Revision 1.3 94/06/14 16:48:03 dcs + * Added support for ODY-like mounting in the kernel (SETS) + * + * Revision 1.2 92/10/27 17:58:28 lily + * merge kernel/latest and alpha/src/cfs + * + * Revision 1.1 92/04/03 17:35:34 satya + * Initial revision + * + * Revision 1.5 91/02/09 12:53:26 jjk + * Substituted rvb's history blurb so that we agree with Mach 2.5 sources. + * + * Revision 2.2.1.1 91/01/06 22:08:22 rvb + * Created for the Coda File System. + * [90/05/23 dcs] + * + * Revision 1.3 90/07/19 10:23:05 dcs + * Added ; to cfs_resize definition for port to 386. + * + * Revision 1.2 90/05/31 17:02:09 dcs + * Prepare for merge with facilities kernel. + * + * + * + */ + +#ifndef _CFSIO_H_ +#define _CFSIO_H_ + +/* Define ioctl commands for vcioctl, /dev/cfs */ + +#ifdef __STDC__ +#define CFSRESIZE _IOW('c', 1, struct cfs_resize ) /* Resize CFS NameCache */ +#define CFSSTATS _IO('c', 2) /* Collect stats */ +#define CFSPRINT _IO('c', 3) /* Print Cache */ +#define CFSTEST _IO('c', 4) /* Print Cache */ +#else /* sys/ioctl.h puts the quotes on */ +#define CFSRESIZE _IOW(c, 1, struct cfs_resize ) /* Resize CFS NameCache */ +#define CFSSTATS _IO(c, 2) /* Collect stats */ +#define CFSPRINT _IO(c, 3) /* Print Cache */ + +#define CFSTEST _IO(c, 4) /* Print Cache */ +#endif __STDC__ + + +struct cfs_resize { int hashsize, heapsize; }; + +#endif !_CFSIO_H_ diff --git a/sys/fs/coda/coda_kernel.h b/sys/fs/coda/coda_kernel.h new file mode 100644 index 0000000..5bdcd41 --- /dev/null +++ b/sys/fs/coda/coda_kernel.h @@ -0,0 +1,64 @@ +/* + + 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. +*/ + +/* $Header: /afs/cs/project/coda-src/cvs/coda/kernel-src/vfs/freebsd/cfs/cfsk.h,v 1.9 1998/08/18 17:05:23 rvb Exp $ */ + +/* Macros to manipulate the queue */ +#ifndef INIT_QUEUE +struct queue { + struct queue *forw, *back; +}; + +#define INIT_QUEUE(head) \ +do { \ + (head).forw = (struct queue *)&(head); \ + (head).back = (struct queue *)&(head); \ +} while (0) + +#define GETNEXT(head) (head).forw + +#define EMPTY(head) ((head).forw == &(head)) + +#define EOQ(el, head) ((struct queue *)(el) == (struct queue *)&(head)) + +#define INSQUE(el, head) \ +do { \ + (el).forw = ((head).back)->forw; \ + (el).back = (head).back; \ + ((head).back)->forw = (struct queue *)&(el); \ + (head).back = (struct queue *)&(el); \ +} while (0) + +#define REMQUE(el) \ +do { \ + ((el).forw)->back = (el).back; \ + (el).back->forw = (el).forw; \ +} while (0) + +#endif INIT_QUEUE diff --git a/sys/fs/coda/coda_namecache.c b/sys/fs/coda/coda_namecache.c new file mode 100644 index 0000000..6c80a26 --- /dev/null +++ b/sys/fs/coda/coda_namecache.c @@ -0,0 +1,898 @@ +/* + + 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. +*/ + +/* $Header: /afs/cs/project/coda-src/cvs/coda/kernel-src/vfs/freebsd/cfs/cfs_namecache.c,v 1.11 1998/08/28 18:12:16 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: cfs_namecache.c,v $ + * 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_CFS1_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 cfs_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 CFS-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 CFS_REPLACE call to allow venus to replace a ViceFid in the + * mini-cache. + * + * In "cfs.h": + * Add CFS_REPLACE decl. + * + * In "cfs_namecache.c": + * Add routine cfsnc_replace. + * + * In "cfs_subr.c": + * Add case-statement to process CFS_REPLACE. + * + * In "cfsnc.h": + * Add decl for CFSNC_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 cfs_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 CFS 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. cfsnc_name(cp) was added to get a name for a cnode pointer for debugging. + * 3. cfsnc_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 +#include +#include + +#if defined(__NetBSD__) || defined(__FreeBSD__) +#ifndef insque +#include +#endif /* insque */ +#endif /* __NetBSD__ || defined(__FreeBSD__) */ + +#ifdef __FreeBSD__ +#include +#include +#ifdef __FreeBSD_version +#include +#endif +#endif + +/* + * Declaration of the name cache data structure. + */ + +int cfsnc_use = 1; /* Indicate use of CFS Name Cache */ + +int cfsnc_size = CFSNC_CACHESIZE; /* size of the cache */ +int cfsnc_hashsize = CFSNC_HASHSIZE; /* size of the primary hash */ + +struct cfscache *cfsncheap; /* pointer to the cache entries */ +struct cfshash *cfsnchash; /* hash table of cfscache pointers */ +struct cfslru cfsnc_lru; /* head of lru chain */ + +struct cfsnc_statistics cfsnc_stat; /* Keep various stats */ + +/* + * for testing purposes + */ +int cfsnc_debug = 0; + + +/* + * Entry points for the CFS Name Cache + */ +static struct cfscache * +cfsnc_find(struct cnode *dcp, const char *name, int namelen, + struct ucred *cred, int hash); +static void +cfsnc_remove(struct cfscache *cncp, enum dc_status dcstat); + + +/* + * Initialize the cache, the LRU structure and the Hash structure(s) + */ + +#define TOTAL_CACHE_SIZE (sizeof(struct cfscache) * cfsnc_size) +#define TOTAL_HASH_SIZE (sizeof(struct cfshash) * cfsnc_hashsize) + +int cfsnc_initialized = 0; /* Initially the cache has not been initialized */ + +void +cfsnc_init(void) +{ + int i; + + /* zero the statistics structure */ + + bzero(&cfsnc_stat, (sizeof(struct cfsnc_statistics))); + + printf("CFS NAME CACHE: CACHE %d, HASH TBL %d\n", CFSNC_CACHESIZE, CFSNC_HASHSIZE); + CFS_ALLOC(cfsncheap, struct cfscache *, TOTAL_CACHE_SIZE); + CFS_ALLOC(cfsnchash, struct cfshash *, TOTAL_HASH_SIZE); + + cfsnc_lru.lru_next = + cfsnc_lru.lru_prev = (struct cfscache *)LRU_PART(&cfsnc_lru); + + + for (i=0; i < cfsnc_size; i++) { /* initialize the heap */ + CFSNC_LRUINS(&cfsncheap[i], &cfsnc_lru); + CFSNC_HSHNUL(&cfsncheap[i]); + cfsncheap[i].cp = cfsncheap[i].dcp = (struct cnode *)0; + } + + for (i=0; i < cfsnc_hashsize; i++) { /* initialize the hashtable */ + CFSNC_HSHNUL((struct cfscache *)&cfsnchash[i]); + } + + cfsnc_initialized++; +} + +/* + * Auxillary routines -- shouldn't be entry points + */ + +static struct cfscache * +cfsnc_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 cfscache *cncp; + int count = 1; + + CFSNC_DEBUG(CFSNC_FIND, + myprintf(("cfsnc_find(dcp %p, name %s, len %d, cred %p, hash %d\n", + dcp, name, namelen, cred, hash));) + + for (cncp = cfsnchash[hash].hash_next; + cncp != (struct cfscache *)&cfsnchash[hash]; + cncp = cncp->hash_next, count++) + { + + if ((CFS_NAMEMATCH(cncp, name, namelen, dcp)) && + ((cred == 0) || (cncp->cred == cred))) + { + /* compare cr_uid instead */ + cfsnc_stat.Search_len += count; + return(cncp); + } +#ifdef DEBUG + else if (CFS_NAMEMATCH(cncp, name, namelen, dcp)) { + printf("cfsnc_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 cfscache *)0); +} + +/* + * Enter a new (dir cnode, name) pair into the cache, updating the + * LRU and Hash as needed. + */ +void +cfsnc_enter(dcp, name, namelen, cred, cp) + struct cnode *dcp; + const char *name; + int namelen; + struct ucred *cred; + struct cnode *cp; +{ + struct cfscache *cncp; + int hash; + + if (cfsnc_use == 0) /* Cache is off */ + return; + + CFSNC_DEBUG(CFSNC_ENTER, + myprintf(("Enter: dcp %p cp %p name %s cred %p \n", + dcp, cp, name, cred)); ) + + if (namelen > CFSNC_NAMELEN) { + CFSNC_DEBUG(CFSNC_ENTER, + myprintf(("long name enter %s\n",name));) + cfsnc_stat.long_name_enters++; /* record stats */ + return; + } + + hash = CFSNC_HASH(name, namelen, dcp); + cncp = cfsnc_find(dcp, name, namelen, cred, hash); + if (cncp != (struct cfscache *) 0) { + cfsnc_stat.dbl_enters++; /* duplicate entry */ + return; + } + + cfsnc_stat.enters++; /* record the enters statistic */ + + /* Grab the next element in the lru chain */ + cncp = CFSNC_LRUGET(cfsnc_lru); + + CFSNC_LRUREM(cncp); /* remove it from the lists */ + + if (CFSNC_VALID(cncp)) { + /* Seems really ugly, but we have to decrement the appropriate + hash bucket length here, so we have to find the hash bucket + */ + cfsnchash[CFSNC_HASH(cncp->name, cncp->namelen, cncp->dcp)].length--; + + cfsnc_stat.lru_rm++; /* zapped a valid entry */ + CFSNC_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. */ + + CFSNC_LRUINS(cncp, &cfsnc_lru); + CFSNC_HSHINS(cncp, &cfsnchash[hash]); + cfsnchash[hash].length++; /* Used for tuning */ + + CFSNC_DEBUG(CFSNC_PRINTCFSNC, print_cfsnc(); ) +} + +/* + * Find the (dir cnode, name) pair in the cache, if it's cred + * matches the input, return it, otherwise return 0 + */ +struct cnode * +cfsnc_lookup(dcp, name, namelen, cred) + struct cnode *dcp; + const char *name; + int namelen; + struct ucred *cred; +{ + int hash; + struct cfscache *cncp; + + if (cfsnc_use == 0) /* Cache is off */ + return((struct cnode *) 0); + + if (namelen > CFSNC_NAMELEN) { + CFSNC_DEBUG(CFSNC_LOOKUP, + myprintf(("long name lookup %s\n",name));) + cfsnc_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 = CFSNC_HASH(name, namelen, dcp); + cncp = cfsnc_find(dcp, name, namelen, cred, hash); + if (cncp == (struct cfscache *) 0) { + cfsnc_stat.misses++; /* record miss */ + return((struct cnode *) 0); + } + + cfsnc_stat.hits++; + + /* put this entry at the end of the LRU */ + CFSNC_LRUREM(cncp); + CFSNC_LRUINS(cncp, &cfsnc_lru); + + /* move it to the front of the hash chain */ + /* don't need to change the hash bucket length */ + CFSNC_HSHREM(cncp); + CFSNC_HSHINS(cncp, &cfsnchash[hash]); + + CFSNC_DEBUG(CFSNC_LOOKUP, + printf("lookup: dcp %p, name %s, cred %p = cp %p\n", + dcp, name, cred, cncp->cp); ) + + return(cncp->cp); +} + +static void +cfsnc_remove(cncp, dcstat) + struct cfscache *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. + */ + CFSNC_DEBUG(CFSNC_REMOVE, + myprintf(("cfsnc_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));) + + CFSNC_HSHREM(cncp); + + CFSNC_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. */ + CFSNC_LRUREM(cncp); + CFSNC_LRUINS(cncp, LRU_TOP(cfsnc_lru.lru_prev)); +} + +/* + * Remove all entries with a parent which has the input fid. + */ +void +cfsnc_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 cfscache *cncp, *ncncp; + int i; + + if (cfsnc_use == 0) /* Cache is off */ + return; + + CFSNC_DEBUG(CFSNC_ZAPPFID, + myprintf(("ZapParent: fid 0x%lx, 0x%lx, 0x%lx \n", + fid->Volume, fid->Vnode, fid->Unique)); ) + + cfsnc_stat.zapPfids++; + + for (i = 0; i < cfsnc_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 = cfsnchash[i].hash_next; + cncp != (struct cfscache *)&cfsnchash[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)) { + cfsnchash[i].length--; /* Used for tuning */ + cfsnc_remove(cncp, dcstat); + } + } + } +} + + +/* + * Remove all entries which have the same fid as the input + */ +void +cfsnc_zapfid(fid, dcstat) + ViceFid *fid; + enum dc_status dcstat; +{ + /* See comment for zapParentfid. This routine will be used + if attributes are being cached. + */ + struct cfscache *cncp, *ncncp; + int i; + + if (cfsnc_use == 0) /* Cache is off */ + return; + + CFSNC_DEBUG(CFSNC_ZAPFID, + myprintf(("Zapfid: fid 0x%lx, 0x%lx, 0x%lx \n", + fid->Volume, fid->Vnode, fid->Unique)); ) + + cfsnc_stat.zapFids++; + + for (i = 0; i < cfsnc_hashsize; i++) { + for (cncp = cfsnchash[i].hash_next; + cncp != (struct cfscache *)&cfsnchash[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)) { + cfsnchash[i].length--; /* Used for tuning */ + cfsnc_remove(cncp, dcstat); + } + } + } +} + +/* + * Remove all entries which match the fid and the cred + */ +void +cfsnc_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 (cfsnc_use == 0) /* Cache is off */ + return; + + CFSNC_DEBUG(CFSNC_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 +cfsnc_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 cfscache *cncp; + int hash; + + if (cfsnc_use == 0) /* Cache is off */ + return; + + CFSNC_DEBUG(CFSNC_ZAPFILE, + myprintf(("Zapfile: dcp %p name %s \n", + dcp, name)); ) + + if (namelen > CFSNC_NAMELEN) { + cfsnc_stat.long_remove++; /* record stats */ + return; + } + + cfsnc_stat.zapFile++; + + hash = CFSNC_HASH(name, namelen, dcp); + cncp = cfsnc_find(dcp, name, namelen, 0, hash); + + while (cncp) { + cfsnchash[hash].length--; /* Used for tuning */ +/* 1.3 */ + cfsnc_remove(cncp, NOT_DOWNCALL); + cncp = cfsnc_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 +cfsnc_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 cfscache *cncp, *ncncp; + int hash; + + if (cfsnc_use == 0) /* Cache is off */ + return; + + CFSNC_DEBUG(CFSNC_PURGEUSER, + myprintf(("ZapDude: uid %lx\n", uid)); ) + cfsnc_stat.zapUsers++; + + for (cncp = CFSNC_LRUGET(cfsnc_lru); + cncp != (struct cfscache *)(&cfsnc_lru); + cncp = ncncp) { + ncncp = CFSNC_LRUGET(*cncp); + + if ((CFSNC_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 = CFSNC_HASH(cncp->name, cncp->namelen, cncp->dcp); + cfsnchash[hash].length--; /* For performance tuning */ + + cfsnc_remove(cncp, dcstat); + } + } +} + +/* + * Flush the entire name cache. In response to a flush of the Venus cache. + */ +void +cfsnc_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 cfscache *cncp; + int i; + + if (cfsnc_use == 0) /* Cache is off */ + return; + + cfsnc_stat.Flushes++; + + for (cncp = CFSNC_LRUGET(cfsnc_lru); + cncp != (struct cfscache *)&cfsnc_lru; + cncp = CFSNC_LRUGET(*cncp)) { + if (CFSNC_VALID(cncp)) { + + CFSNC_HSHREM(cncp); /* only zero valid nodes */ + CFSNC_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 (cfs_vmflush(cncp->cp)) + CFSDEBUG(CFS_FLUSH, + myprintf(("cfsnc_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 < cfsnc_hashsize; i++) + cfsnchash[i].length = 0; +} + +/* + * Debugging routines + */ + +/* + * This routine should print out all the hash chains to the console. + */ +void +print_cfsnc(void) +{ + int hash; + struct cfscache *cncp; + + for (hash = 0; hash < cfsnc_hashsize; hash++) { + myprintf(("\nhash %d\n",hash)); + + for (cncp = cfsnchash[hash].hash_next; + cncp != (struct cfscache *)&cfsnchash[hash]; + cncp = cncp->hash_next) { + myprintf(("cp %p dcp %p cred %p name %s\n", + cncp->cp, cncp->dcp, + cncp->cred, cncp->name)); + } + } +} + +void +cfsnc_gather_stats(void) +{ + int i, max = 0, sum = 0, temp, zeros = 0, ave, n; + + for (i = 0; i < cfsnc_hashsize; i++) { + if (cfsnchash[i].length) { + sum += cfsnchash[i].length; + } else { + zeros++; + } + + if (cfsnchash[i].length > max) + max = cfsnchash[i].length; + } + + /* + * When computing the Arithmetic mean, only count slots which + * are not empty in the distribution. + */ + cfsnc_stat.Sum_bucket_len = sum; + cfsnc_stat.Num_zero_len = zeros; + cfsnc_stat.Max_bucket_len = max; + + if ((n = cfsnc_hashsize - zeros) > 0) + ave = sum / n; + else + ave = 0; + + sum = 0; + for (i = 0; i < cfsnc_hashsize; i++) { + if (cfsnchash[i].length) { + temp = cfsnchash[i].length - ave; + sum += temp * temp; + } + } + cfsnc_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 +cfsnc_resize(hashsize, heapsize, dcstat) + int hashsize, heapsize; + enum dc_status dcstat; +{ + if ((hashsize % 2) || (heapsize % 2)) { /* Illegal hash or cache sizes */ + return(EINVAL); + } + + cfsnc_use = 0; /* Turn the cache off */ + + cfsnc_flush(dcstat); /* free any cnodes in the cache */ + + /* WARNING: free must happen *before* size is reset */ + CFS_FREE(cfsncheap,TOTAL_CACHE_SIZE); + CFS_FREE(cfsnchash,TOTAL_HASH_SIZE); + + cfsnc_hashsize = hashsize; + cfsnc_size = heapsize; + + cfsnc_init(); /* Set up a cache with the new size */ + + cfsnc_use = 1; /* Turn the cache back on */ + return(0); +} + +#define DEBUG +#ifdef DEBUG +char cfsnc_name_buf[CFS_MAXNAMLEN+1]; + +void +cfsnc_name(struct cnode *cp) +{ + struct cfscache *cncp, *ncncp; + int i; + + if (cfsnc_use == 0) /* Cache is off */ + return; + + for (i = 0; i < cfsnc_hashsize; i++) { + for (cncp = cfsnchash[i].hash_next; + cncp != (struct cfscache *)&cfsnchash[i]; + cncp = ncncp) { + ncncp = cncp->hash_next; + if (cncp->cp == cp) { + bcopy(cncp->name, cfsnc_name_buf, cncp->namelen); + cfsnc_name_buf[cncp->namelen] = 0; + printf(" is %s (%p,%p)@%p", + cfsnc_name_buf, cncp->cp, cncp->dcp, cncp); + } + + } + } +} +#endif diff --git a/sys/fs/coda/coda_namecache.h b/sys/fs/coda/coda_namecache.h new file mode 100644 index 0000000..86ed38c --- /dev/null +++ b/sys/fs/coda/coda_namecache.h @@ -0,0 +1,273 @@ +/* + + 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. +*/ + +/* $Header: /afs/cs/project/coda-src/cvs/coda/kernel-src/vfs/freebsd/cfs/cfsnc.h,v 1.8 1998/08/28 18:12:25 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: cfsnc.h,v $ + * Revision 1.8 1998/08/28 18:12:25 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.7 1998/08/18 17:05:24 rvb + * Don't use __RCSID now + * + * Revision 1.6 1998/08/18 16:31:49 rvb + * Sync the code for NetBSD -current; test on 1.3 later + * + * Revision 1.5 98/01/23 11:53:51 rvb + * Bring RVB_CFS1_1 to HEAD + * + * Revision 1.4.2.1 97/12/16 12:40:23 rvb + * Sync with 1.3 + * + * Revision 1.4 97/12/05 10:39:29 rvb + * Read CHANGES + * + * Revision 1.3.4.3 97/11/24 15:44:51 rvb + * Final cfs_venus.c w/o macros, but one locking bug + * + * Revision 1.3.4.2 97/11/12 12:09:44 rvb + * reorg pass1 + * + * Revision 1.3.4.1 97/11/06 21:06:05 rvb + * don't include headers in headers + * + * Revision 1.3 97/08/05 11:08:19 lily + * Removed cfsnc_replace, replaced it with a cfs_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.2 96/01/02 16:57:19 bnoble + * Added support for Coda MiniCache and raw inode calls (final commit) + * + * Revision 1.1.2.1 1995/12/20 01:57:45 bnoble + * Added CFS-specific files + * + * Revision 3.1.1.1 1995/03/04 19:08:22 bnoble + * Branch for NetBSD port revisions + * + * Revision 3.1 1995/03/04 19:08:21 bnoble + * Bump to major revision 3 to prepare for NetBSD port + * + * Revision 2.2 1994/08/28 19:37:39 luqi + * Add a new CFS_REPLACE call to allow venus to replace a ViceFid in the + * mini-cache. + * + * In "cfs.h": + * Add CFS_REPLACE decl. + * + * In "cfs_namecache.c": + * Add routine cfsnc_replace. + * + * In "cfs_subr.c": + * Add case-statement to process CFS_REPLACE. + * + * In "cfsnc.h": + * Add decl for CFSNC_REPLACE. + * + * Revision 2.1 94/07/21 16:25:27 satya + * Conversion to C++ 3.0; start of Coda Release 2.0 + * + * Revision 1.2 92/10/27 17:58:34 lily + * merge kernel/latest and alpha/src/cfs + * + * Revision 2.2 90/07/05 11:27:04 mrt + * Created for the Coda File System. + * [90/05/23 dcs] + * + * Revision 1.4 90/05/31 17:02:12 dcs + * Prepare for merge with facilities kernel. + * + * + */ +#ifndef _CFSNC_HEADER_ +#define _CFSNC_HEADER_ + +/* + * Cfs constants + */ +#define CFSNC_NAMELEN 15 /* longest name stored in cache */ +#define CFSNC_CACHESIZE 256 /* Default cache size */ +#define CFSNC_HASHSIZE 64 /* Must be multiple of 2 */ + +/* + * Hash function for the primary hash. + */ + +/* + * First try -- (first + last letters + length + (int)cp) mod size + * 2nd try -- same, except dir fid.vnode instead of cp + */ + +#ifdef oldhash +#define CFSNC_HASH(name, namelen, cp) \ + ((name[0] + name[namelen-1] + namelen + (int)(cp)) & (cfsnc_hashsize-1)) +#else +#define CFSNC_HASH(name, namelen, cp) \ + ((name[0] + (name[namelen-1]<<4) + namelen + (((int)cp)>>8)) & (cfsnc_hashsize-1)) +#endif + +#define CFS_NAMEMATCH(cp, name, namelen, dcp) \ + ((namelen == cp->namelen) && (dcp == cp->dcp) && \ + (bcmp(cp->name,name,namelen) == 0)) + +/* + * Functions to modify the hash and lru chains. + * insque and remque assume that the pointers are the first thing + * in the list node, thus the trickery for lru. + */ + +#define CFSNC_HSHINS(elem, pred) insque(elem,pred) +#define CFSNC_HSHREM(elem) remque(elem) +#define CFSNC_HSHNUL(elem) (elem)->hash_next = \ + (elem)->hash_prev = (elem) + +#define CFSNC_LRUINS(elem, pred) insque(LRU_PART(elem), LRU_PART(pred)) +#define CFSNC_LRUREM(elem) remque(LRU_PART(elem)); +#define CFSNC_LRUGET(lruhead) LRU_TOP((lruhead).lru_prev) + +#define CFSNC_VALID(cncp) (cncp->dcp != (struct cnode *)0) + +#define LRU_PART(cncp) (struct cfscache *) \ + ((char *)cncp + (2*sizeof(struct cfscache *))) +#define LRU_TOP(cncp) (struct cfscache *) \ + ((char *)cncp - (2*sizeof(struct cfscache *))) +#define DATA_PART(cncp) (struct cfscache *) \ + ((char *)cncp + (4*sizeof(struct cfscache *))) +#define DATA_SIZE (sizeof(struct cfscache)-(4*sizeof(struct cfscache *))) + +/* + * Structure for an element in the CFS Name Cache. + * NOTE: I use the position of arguments and their size in the + * implementation of the functions CFSNC_LRUINS, CFSNC_LRUREM, and + * DATA_PART. + */ + +struct cfscache { + struct cfscache *hash_next,*hash_prev; /* Hash list */ + struct cfscache *lru_next, *lru_prev; /* LRU list */ + struct cnode *cp; /* vnode of the file */ + struct cnode *dcp; /* parent's cnode */ + struct ucred *cred; /* user credentials */ + char name[CFSNC_NAMELEN]; /* segment name */ + int namelen; /* length of name */ +}; + +struct cfslru { /* Start of LRU chain */ + char *dummy1, *dummy2; /* place holders */ + struct cfscache *lru_next, *lru_prev; /* position of pointers is important */ +}; + + +struct cfshash { /* Start of Hash chain */ + struct cfscache *hash_next, *hash_prev; /* NOTE: chain pointers must be first */ + int length; /* used for tuning purposes */ +}; + + +/* + * Symbols to aid in debugging the namecache code. Assumes the existence + * of the variable cfsnc_debug, which is defined in cfs_namecache.c + */ +#define CFSNC_DEBUG(N, STMT) { if (cfsnc_debug & (1 < pioctl.h + * + * Revision 1.2 96/01/02 16:57:27 bnoble + * Added support for Coda MiniCache and raw inode calls (final commit) + * + * Revision 1.1.2.1 1995/12/20 01:57:54 bnoble + * Added CFS-specific files + * + * Revision 2.4 90/08/30 11:51:12 bohman + * Ioctl changes for STDC. + * [90/08/28 bohman] + * + * Revision 2.3 89/03/09 22:10:26 rpd + * More cleanup. + * + * Revision 2.2 89/02/25 17:58:32 gm0w + * Changes for cleanup. + * + * 7-Feb-87 Avadis Tevanian (avie) at Carnegie-Mellon University + * No need for VICE conditional. + * + * 22-Oct-86 Jay Kistler (jjk) at Carnegie-Mellon University + * Created from Andrew's vice.h and viceioctl.h. + * + */ +/* + * ITC Remote file system - vice ioctl interface module + */ + +/* + * TODO: Find /usr/local/include/viceioctl.h. + */ + +#ifndef _SYS_PIOCTL_H_ +#define _SYS_PIOCTL_H_ + +/* The 2K limits above are a consequence of the size of the kernel buffer + used to buffer requests from the user to venus--2*MAXPATHLEN. + The buffer pointers may be null, or the counts may be 0 if there + are no input or output parameters + */ + +#ifdef __STDC__ +#define _VICEIOCTL(id) ((unsigned int ) _IOW('V', id, struct ViceIoctl)) +#else +#define _VICEIOCTL(id) ((unsigned int ) _IOW(V, id, struct ViceIoctl)) +#endif +/* Use this macro to define up to 256 vice ioctl's. These ioctl's + all potentially have in/out parameters--this depends upon the + values in the ViceIoctl structure. This structure is itself passed + into the kernel by the normal ioctl parameter passing mechanism. + */ + +#define _VALIDVICEIOCTL(com) (com >= _VICEIOCTL(0) && com <= _VICEIOCTL(255)) + +#endif _SYS_PIOCTL_H_ diff --git a/sys/fs/coda/coda_psdev.c b/sys/fs/coda/coda_psdev.c new file mode 100644 index 0000000..47b4754 --- /dev/null +++ b/sys/fs/coda/coda_psdev.c @@ -0,0 +1,756 @@ +/* + + 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. +*/ + +/* $Header: /afs/cs/project/coda-src/cvs/coda/kernel-src/vfs/freebsd/cfs/cfs_psdev.c,v 1.9 1998/08/28 18:12:17 rvb Exp $ */ + +#define CTL_C + +/* + * 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. */ + +/* ************************************************** */ +/* These routines define the psuedo device for communication between + * Coda's Venus and Minicache in Mach 2.6. They used to be in cfs_subr.c, + * but I moved them to make it easier to port the Minicache without + * porting coda. -- DCS 10/12/94 + */ + +/* + * Renamed to cfs_psdev: pseudo-device driver. + */ + +/* + * HISTORY + * $Log: cfs_psdev.c,v $ + * Revision 1.9 1998/08/28 18:12:17 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.8 1998/08/18 17:05:15 rvb + * Don't use __RCSID now + * + * Revision 1.7 1998/08/18 16:31:41 rvb + * Sync the code for NetBSD -current; test on 1.3 later + * + * Revision 1.8 1998/06/09 23:30:42 rvb + * Try to allow ^C -- take 1 + * + * Revision 1.5.2.8 98/01/23 11:21:04 rvb + * Sync with 2.2.5 + * + * Revision 1.5.2.7 98/01/22 22:22:21 rvb + * sync 1.2 and 1.3 + * + * Revision 1.5.2.6 98/01/22 13:11:24 rvb + * Move makecfsnode ctlfid later so vfsp is known; work on ^c and ^z + * + * Revision 1.5.2.5 97/12/16 22:01:27 rvb + * Oops add cfs_subr.h cfs_venus.h; sync with peter + * + * Revision 1.5.2.4 97/12/16 12:40:05 rvb + * Sync with 1.3 + * + * Revision 1.5.2.3 97/12/10 14:08:24 rvb + * Fix O_ flags; check result in cfscall + * + * Revision 1.5.2.2 97/12/10 11:40:24 rvb + * No more ody + * + * Revision 1.5.2.1 97/12/06 17:41:20 rvb + * Sync with peters coda.h + * + * Revision 1.5 97/12/05 10:39:16 rvb + * Read CHANGES + * + * Revision 1.4.18.9 97/12/05 08:58:07 rvb + * peter found this one + * + * Revision 1.4.18.8 97/11/26 15:28:57 rvb + * Cant make downcall pbuf == union cfs_downcalls yet + * + * Revision 1.4.18.7 97/11/25 09:40:49 rvb + * Final cfs_venus.c w/o macros, but one locking bug + * + * Revision 1.4.18.6 97/11/20 11:46:41 rvb + * Capture current cfs_venus + * + * Revision 1.4.18.5 97/11/18 10:27:15 rvb + * cfs_nbsd.c is DEAD!!!; integrated into cfs_vf/vnops.c + * cfs_nb_foo and cfs_foo are joined + * + * Revision 1.4.18.4 97/11/13 22:02:59 rvb + * pass2 cfs_NetBSD.h mt + * + * Revision 1.4.18.3 97/11/12 12:09:38 rvb + * reorg pass1 + * + * Revision 1.4.18.2 97/10/29 16:06:09 rvb + * Kill DYING + * + * Revision 1.4.18.1 1997/10/28 23:10:15 rvb + * >64Meg; venus can be killed! + * + * Revision 1.4 1996/12/12 22:10:58 bnoble + * Fixed the "downcall invokes venus operation" deadlock in all known cases. + * There may be more + * + * Revision 1.3 1996/11/13 04:14:20 bnoble + * Merging BNOBLE_WORK_6_20_96 into main line + * + * Revision 1.2.8.1 1996/08/22 14:25:04 bnoble + * Added a return code from vc_nb_close + * + * Revision 1.2 1996/01/02 16:56:58 bnoble + * Added support for Coda MiniCache and raw inode calls (final commit) + * + * Revision 1.1.2.1 1995/12/20 01:57:24 bnoble + * Added CFS-specific files + * + * Revision 1.1 1995/03/14 20:52:15 bnoble + * Initial revision + * + */ + +/* These routines are the device entry points for Venus. */ + +extern int cfsnc_initialized; /* Set if cache has been initialized */ + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __FreeBSD_version +#include +#else +#include +#endif +#ifdef NetBSD1_3 +#include +#endif +#ifdef __FreeBSD_version +#include +#else +#include +#endif + +#include +#include +#include +#include + +int cfs_psdev_print_entry = 0; + +#ifdef __GNUC__ +#define ENTRY \ + if(cfs_psdev_print_entry) myprintf(("Entered %s\n",__FUNCTION__)) +#else +#define ENTRY +#endif + +void vcfsattach(int n); +int vc_nb_open(dev_t dev, int flag, int mode, struct proc *p); +int vc_nb_close (dev_t dev, int flag, int mode, struct proc *p); +int vc_nb_read(dev_t dev, struct uio *uiop, int flag); +int vc_nb_write(dev_t dev, struct uio *uiop, int flag); +int vc_nb_ioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p); +#if defined(NetBSD1_3) || defined(__FreeBSD_version) +int vc_nb_poll(dev_t dev, int events, struct proc *p); +#else +int vc_nb_select(dev_t dev, int flag, struct proc *p); +#endif + +struct vmsg { + struct queue vm_chain; + caddr_t vm_data; + u_short vm_flags; + u_short vm_inSize; /* Size is at most 5000 bytes */ + u_short vm_outSize; + u_short vm_opcode; /* copied from data to save ptr lookup */ + int vm_unique; + caddr_t vm_sleep; /* Not used by Mach. */ +}; + +#define VM_READ 1 +#define VM_WRITE 2 +#define VM_INTR 4 + +/* vcfsattach: do nothing */ +void +vcfsattach(n) + int n; +{ +} + +/* + * These functions are written for NetBSD. + */ +int +vc_nb_open(dev, flag, mode, p) + dev_t dev; + int flag; + int mode; + struct proc *p; /* NetBSD only */ +{ + register struct vcomm *vcp; + + ENTRY; + + if (minor(dev) >= NVCFS || minor(dev) < 0) + return(ENXIO); + + if (!cfsnc_initialized) + cfsnc_init(); + + vcp = &cfs_mnttbl[minor(dev)].mi_vcomm; + if (VC_OPEN(vcp)) + return(EBUSY); + + bzero(&(vcp->vc_selproc), sizeof (struct selinfo)); + INIT_QUEUE(vcp->vc_requests); + INIT_QUEUE(vcp->vc_replys); + MARK_VC_OPEN(vcp); + + cfs_mnttbl[minor(dev)].mi_vfsp = NULL; + cfs_mnttbl[minor(dev)].mi_rootvp = NULL; + + return(0); +} + +int +vc_nb_close (dev, flag, mode, p) + dev_t dev; + int flag; + int mode; + struct proc *p; +{ + register struct vcomm *vcp; + register struct vmsg *vmp; + struct cfs_mntinfo *mi; + int err; + + ENTRY; + + if (minor(dev) >= NVCFS || minor(dev) < 0) + return(ENXIO); + + mi = &cfs_mnttbl[minor(dev)]; + vcp = &(mi->mi_vcomm); + + if (!VC_OPEN(vcp)) + panic("vcclose: not open"); + + /* prevent future operations on this vfs from succeeding by auto- + * unmounting any vfs mounted via this device. This frees user or + * sysadm from having to remember where all mount points are located. + * Put this before WAKEUPs to avoid queuing new messages between + * the WAKEUP and the unmount (which can happen if we're unlucky) + */ + if (mi->mi_rootvp) { + /* Let unmount know this is for real */ + VTOC(mi->mi_rootvp)->c_flags |= C_UNMOUNTING; +#ifdef NEW_LOCKMGR +#ifdef __FreeBSD_version + /* dounmount is different ... probably wrong ... */ +#else + if (vfs_busy(mi->mi_vfsp, 0, 0)) + return (EBUSY); +#endif +#endif + cfs_unmounting(mi->mi_vfsp); + err = dounmount(mi->mi_vfsp, flag, p); + if (err) + myprintf(("Error %d unmounting vfs in vcclose(%d)\n", + err, minor(dev))); + } + + /* Wakeup clients so they can return. */ + for (vmp = (struct vmsg *)GETNEXT(vcp->vc_requests); + !EOQ(vmp, vcp->vc_requests); + vmp = (struct vmsg *)GETNEXT(vmp->vm_chain)) + { + /* Free signal request messages and don't wakeup cause + no one is waiting. */ + if (vmp->vm_opcode == CFS_SIGNAL) { + CFS_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA); + CFS_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg)); + continue; + } + + wakeup(&vmp->vm_sleep); + } + + for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys); + !EOQ(vmp, vcp->vc_replys); + vmp = (struct vmsg *)GETNEXT(vmp->vm_chain)) + { + wakeup(&vmp->vm_sleep); + } + + MARK_VC_CLOSED(vcp); + return 0; +} + +int +vc_nb_read(dev, uiop, flag) + dev_t dev; + struct uio *uiop; + int flag; +{ + register struct vcomm * vcp; + register struct vmsg *vmp; + int error = 0; + + ENTRY; + + if (minor(dev) >= NVCFS || minor(dev) < 0) + return(ENXIO); + + vcp = &cfs_mnttbl[minor(dev)].mi_vcomm; + /* Get message at head of request queue. */ + if (EMPTY(vcp->vc_requests)) + return(0); /* Nothing to read */ + + vmp = (struct vmsg *)GETNEXT(vcp->vc_requests); + + /* Move the input args into userspace */ + uiop->uio_rw = UIO_READ; + error = uiomove(vmp->vm_data, vmp->vm_inSize, uiop); + if (error) { + myprintf(("vcread: error (%d) on uiomove\n", error)); + error = EINVAL; + } + +#ifdef DIAGNOSTIC + if (vmp->vm_chain.forw == 0 || vmp->vm_chain.back == 0) + panic("vc_nb_read: bad chain"); +#endif + + REMQUE(vmp->vm_chain); + + /* If request was a signal, free up the message and don't + enqueue it in the reply queue. */ + if (vmp->vm_opcode == CFS_SIGNAL) { + if (cfsdebug) + myprintf(("vcread: signal msg (%d, %d)\n", + vmp->vm_opcode, vmp->vm_unique)); + CFS_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA); + CFS_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg)); + return(error); + } + + vmp->vm_flags |= VM_READ; + INSQUE(vmp->vm_chain, vcp->vc_replys); + + return(error); +} + +int +vc_nb_write(dev, uiop, flag) + dev_t dev; + struct uio *uiop; + int flag; +{ + register struct vcomm * vcp; + register struct vmsg *vmp; + struct cfs_out_hdr *out; + u_long seq; + u_long opcode; + int buf[2]; + int error = 0; + + ENTRY; + + if (minor(dev) >= NVCFS || minor(dev) < 0) + return(ENXIO); + + vcp = &cfs_mnttbl[minor(dev)].mi_vcomm; + + /* Peek at the opcode, unique without transfering the data. */ + uiop->uio_rw = UIO_WRITE; + error = uiomove((caddr_t)buf, sizeof(int) * 2, uiop); + if (error) { + myprintf(("vcwrite: error (%d) on uiomove\n", error)); + return(EINVAL); + } + + opcode = buf[0]; + seq = buf[1]; + + if (cfsdebug) + myprintf(("vcwrite got a call for %ld.%ld\n", opcode, seq)); + + if (DOWNCALL(opcode)) { + union outputArgs pbuf; + + /* get the rest of the data. */ + uiop->uio_rw = UIO_WRITE; + error = uiomove((caddr_t)&pbuf.cfs_purgeuser.oh.result, sizeof(pbuf) - (sizeof(int)*2), uiop); + if (error) { + myprintf(("vcwrite: error (%d) on uiomove (Op %ld seq %ld)\n", + error, opcode, seq)); + return(EINVAL); + } + + return handleDownCall(opcode, &pbuf); + } + + /* Look for the message on the (waiting for) reply queue. */ + for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys); + !EOQ(vmp, vcp->vc_replys); + vmp = (struct vmsg *)GETNEXT(vmp->vm_chain)) + { + if (vmp->vm_unique == seq) break; + } + + if (EOQ(vmp, vcp->vc_replys)) { + if (cfsdebug) + myprintf(("vcwrite: msg (%ld, %ld) not found\n", opcode, seq)); + + return(ESRCH); + } + + /* Remove the message from the reply queue */ + REMQUE(vmp->vm_chain); + + /* move data into response buffer. */ + out = (struct cfs_out_hdr *)vmp->vm_data; + /* Don't need to copy opcode and uniquifier. */ + + /* get the rest of the data. */ + if (vmp->vm_outSize < uiop->uio_resid) { + myprintf(("vcwrite: more data than asked for (%d < %d)\n", + vmp->vm_outSize, uiop->uio_resid)); + wakeup(&vmp->vm_sleep); /* Notify caller of the error. */ + return(EINVAL); + } + + buf[0] = uiop->uio_resid; /* Save this value. */ + uiop->uio_rw = UIO_WRITE; + error = uiomove((caddr_t) &out->result, vmp->vm_outSize - (sizeof(int) * 2), uiop); + if (error) { + myprintf(("vcwrite: error (%d) on uiomove (op %ld seq %ld)\n", + error, opcode, seq)); + return(EINVAL); + } + + /* I don't think these are used, but just in case. */ + /* XXX - aren't these two already correct? -bnoble */ + out->opcode = opcode; + out->unique = seq; + vmp->vm_outSize = buf[0]; /* Amount of data transferred? */ + vmp->vm_flags |= VM_WRITE; + wakeup(&vmp->vm_sleep); + + return(0); +} + +int +vc_nb_ioctl(dev, cmd, addr, flag, p) + dev_t dev; + int cmd; + caddr_t addr; + int flag; + struct proc *p; +{ + ENTRY; + + switch(cmd) { + case CFSRESIZE: { + struct cfs_resize *data = (struct cfs_resize *)addr; + return(cfsnc_resize(data->hashsize, data->heapsize, IS_DOWNCALL)); + break; + } + case CFSSTATS: + if (cfsnc_use) { + cfsnc_gather_stats(); + return(0); + } else { + return(ENODEV); + } + break; + case CFSPRINT: + if (cfsnc_use) { + print_cfsnc(); + return(0); + } else { + return(ENODEV); + } + break; + default : + return(EINVAL); + break; + } +} + +#if defined(NetBSD1_3) || defined(__FreeBSD_version) +int +vc_nb_poll(dev, events, p) + dev_t dev; + int events; + struct proc *p; +{ + register struct vcomm *vcp; + int event_msk = 0; + + ENTRY; + + if (minor(dev) >= NVCFS || minor(dev) < 0) + return(ENXIO); + + vcp = &cfs_mnttbl[minor(dev)].mi_vcomm; + + event_msk = events & (POLLIN|POLLRDNORM); + if (!event_msk) + return(0); + + if (!EMPTY(vcp->vc_requests)) + return(events & (POLLIN|POLLRDNORM)); + + selrecord(p, &(vcp->vc_selproc)); + + return(0); +} +#else +int +vc_nb_select(dev, flag, p) + dev_t dev; + int flag; + struct proc *p; +{ + register struct vcomm *vcp; + + ENTRY; + + if (minor(dev) >= NVCFS || minor(dev) < 0) + return(ENXIO); + + vcp = &cfs_mnttbl[minor(dev)].mi_vcomm; + + if (flag != FREAD) + return(0); + + if (!EMPTY(vcp->vc_requests)) + return(1); + + selrecord(p, &(vcp->vc_selproc)); + + return(0); +} +#endif + +/* + * Statistics + */ +struct cfs_clstat cfs_clstat; + +/* + * Key question: whether to sleep interuptably or uninteruptably when + * waiting for Venus. The former seems better (cause you can ^C a + * job), but then GNU-EMACS completion breaks. Use tsleep with no + * timeout, and no longjmp happens. But, when sleeping + * "uninterruptibly", we don't get told if it returns abnormally + * (e.g. kill -9). + */ + +/* If you want this to be interruptible, set this to > PZERO */ +int cfscall_sleep = PZERO - 1; +#ifdef CTL_C +int cfs_pcatch = PCATCH; +#else +#endif + +int +cfscall(mntinfo, inSize, outSize, buffer) + struct cfs_mntinfo *mntinfo; int inSize; int *outSize; caddr_t buffer; +{ + struct vcomm *vcp; + struct vmsg *vmp; + int error; +#ifdef CTL_C + struct proc *p = curproc; + unsigned int psig_omask = p->p_sigmask; + int i; +#endif + if (mntinfo == NULL) { + /* Unlikely, but could be a race condition with a dying warden */ + return ENODEV; + } + + vcp = &(mntinfo->mi_vcomm); + + cfs_clstat.ncalls++; + cfs_clstat.reqs[((struct cfs_in_hdr *)buffer)->opcode]++; + + if (!VC_OPEN(vcp)) + return(ENODEV); + + CFS_ALLOC(vmp,struct vmsg *,sizeof(struct vmsg)); + /* Format the request message. */ + vmp->vm_data = buffer; + vmp->vm_flags = 0; + vmp->vm_inSize = inSize; + vmp->vm_outSize + = *outSize ? *outSize : inSize; /* |buffer| >= inSize */ + vmp->vm_opcode = ((struct cfs_in_hdr *)buffer)->opcode; + vmp->vm_unique = ++vcp->vc_seq; + if (cfsdebug) + myprintf(("Doing a call for %d.%d\n", + vmp->vm_opcode, vmp->vm_unique)); + + /* Fill in the common input args. */ + ((struct cfs_in_hdr *)buffer)->unique = vmp->vm_unique; + + /* Append msg to request queue and poke Venus. */ + INSQUE(vmp->vm_chain, vcp->vc_requests); + selwakeup(&(vcp->vc_selproc)); + + /* We can be interrupted while we wait for Venus to process + * our request. If the interrupt occurs before Venus has read + * the request, we dequeue and return. If it occurs after the + * read but before the reply, we dequeue, send a signal + * message, and return. If it occurs after the reply we ignore + * it. In no case do we want to restart the syscall. If it + * was interrupted by a venus shutdown (vcclose), return + * ENODEV. */ + + /* Ignore return, We have to check anyway */ +#ifdef CTL_C + /* This is work in progress. Setting cfs_pcatch lets tsleep reawaken + on a ^c or ^z. The problem is that emacs sets certain interrupts + as SA_RESTART. This means that we should exit sleep handle the + "signal" and then go to sleep again. Mostly this is done by letting + the syscall complete and be restarted. We are not idempotent and + can not do this. A better solution is necessary. + */ + i = 0; + do { + error = tsleep(&vmp->vm_sleep, (cfscall_sleep|cfs_pcatch), "cfscall", hz*2); + if (error == 0) + break; + else if (error == EWOULDBLOCK) { + printf("cfscall: tsleep TIMEOUT %d sec\n", 2+2*i); + } else if (p->p_siglist == sigmask(SIGIO)) { + p->p_sigmask |= p->p_siglist; + printf("cfscall: tsleep returns %d SIGIO, cnt %d\n", error, i); + } else { + printf("cfscall: tsleep returns %d, cnt %d\n", error, i); + printf("cfscall: siglist = %x, sigmask = %x, mask %x\n", + p->p_siglist, p->p_sigmask, + p->p_siglist & ~p->p_sigmask); + break; + p->p_sigmask |= p->p_siglist; + printf("cfscall: new mask, siglist = %x, sigmask = %x, mask %x\n", + p->p_siglist, p->p_sigmask, + p->p_siglist & ~p->p_sigmask); + } + } while (error && i++ < 128); + p->p_sigmask = psig_omask; +#else + (void) tsleep(&vmp->vm_sleep, cfscall_sleep, "cfscall", 0); +#endif + if (VC_OPEN(vcp)) { /* Venus is still alive */ + /* Op went through, interrupt or not... */ + if (vmp->vm_flags & VM_WRITE) { + error = 0; + *outSize = vmp->vm_outSize; + } + + else if (!(vmp->vm_flags & VM_READ)) { + /* Interrupted before venus read it. */ + if (cfsdebug||1) + myprintf(("interrupted before read: op = %d.%d, flags = %x\n", + vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags)); + REMQUE(vmp->vm_chain); + error = EINTR; + } + + else { + /* (!(vmp->vm_flags & VM_WRITE)) means interrupted after + upcall started */ + /* Interrupted after start of upcall, send venus a signal */ + struct cfs_in_hdr *dog; + struct vmsg *svmp; + + if (cfsdebug||1) + myprintf(("Sending Venus a signal: op = %d.%d, flags = %x\n", + vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags)); + + REMQUE(vmp->vm_chain); + error = EINTR; + + CFS_ALLOC(svmp, struct vmsg *, sizeof (struct vmsg)); + + CFS_ALLOC((svmp->vm_data), char *, sizeof (struct cfs_in_hdr)); + dog = (struct cfs_in_hdr *)svmp->vm_data; + + svmp->vm_flags = 0; + dog->opcode = svmp->vm_opcode = CFS_SIGNAL; + dog->unique = svmp->vm_unique = vmp->vm_unique; + svmp->vm_inSize = sizeof (struct cfs_in_hdr); +/*??? rvb */ svmp->vm_outSize = sizeof (struct cfs_in_hdr); + + if (cfsdebug) + myprintf(("cfscall: enqueing signal msg (%d, %d)\n", + svmp->vm_opcode, svmp->vm_unique)); + + /* insert at head of queue! */ + INSQUE(svmp->vm_chain, vcp->vc_requests); + selwakeup(&(vcp->vc_selproc)); + } + } + + else { /* If venus died (!VC_OPEN(vcp)) */ + if (cfsdebug) + myprintf(("vcclose woke op %d.%d flags %d\n", + vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags)); + + error = ENODEV; + } + + CFS_FREE(vmp, sizeof(struct vmsg)); + + if (!error) + error = ((struct cfs_out_hdr *)buffer)->result; + return(error); +} diff --git a/sys/fs/coda/coda_subr.c b/sys/fs/coda/coda_subr.c new file mode 100644 index 0000000..3d20e57 --- /dev/null +++ b/sys/fs/coda/coda_subr.c @@ -0,0 +1,750 @@ +/* + + 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. +*/ + +/* $Header: /afs/cs/project/coda-src/cvs/coda/kernel-src/vfs/freebsd/cfs/cfs_subr.c,v 1.11 1998/08/28 18:12:18 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: cfs_subr.c,v $ + * 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_CFS1_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 cfs_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 CFS-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 cfs_flush routine in place of the former cfsnc_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 cfs_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 cfs_unmounted might try to force flushes to venus. + * The vnode pager does this. + * 2. cfs_unmounting marks all cnodes scanning cfs_cache. + * 3. cfs_checkunmounting (under DEBUG) checks all cnodes by chasing the vnodes + * under the /coda mount point. + * 4. cfs_cacheprint (under DEBUG) prints names with vnode/cnode address + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#if NVCFS + +int cfs_active = 0; +int cfs_reuse = 0; +int cfs_new = 0; + +struct cnode *cfs_freelist = NULL; +struct cnode *cfs_cache[CFS_CACHESIZE]; + +#define cfshash(fid) \ + (((fid)->Volume + (fid)->Vnode) & (CFS_CACHESIZE-1)) + +#define CNODE_NEXT(cp) ((cp)->c_next) + +#define ODD(vnode) ((vnode) & 0x1) + +/* + * Allocate a cnode. + */ +struct cnode * +cfs_alloc(void) +{ + struct cnode *cp; + + if (cfs_freelist) { + cp = cfs_freelist; + cfs_freelist = CNODE_NEXT(cp); + cfs_reuse++; + } + else { + CFS_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)); + cfs_new++; + } + bzero(cp, sizeof (struct cnode)); + + return(cp); +} + +/* + * Deallocate a cnode. + */ +void +cfs_free(cp) + register struct cnode *cp; +{ + + CNODE_NEXT(cp) = cfs_freelist; + cfs_freelist = cp; +} + +/* + * Put a cnode in the hash table + */ +void +cfs_save(cp) + struct cnode *cp; +{ + CNODE_NEXT(cp) = cfs_cache[cfshash(&cp->c_fid)]; + cfs_cache[cfshash(&cp->c_fid)] = cp; +} + +/* + * Remove a cnode from the hash table + */ +void +cfs_unsave(cp) + struct cnode *cp; +{ + struct cnode *ptr; + struct cnode *ptrprev = NULL; + + ptr = cfs_cache[cfshash(&cp->c_fid)]; + while (ptr != NULL) { + if (ptr == cp) { + if (ptrprev == NULL) { + cfs_cache[cfshash(&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 * +cfs_find(fid) + ViceFid *fid; +{ + struct cnode *cp; + + cp = cfs_cache[cfshash(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))) + { + cfs_active++; + return(cp); + } + cp = CNODE_NEXT(cp); + } + return(NULL); +} + +/* + * cfs_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 + * cfs_inactive of course!). Since multiple venii/wardens can be + * running, only kill the cnodes for a particular entry in the + * cfs_mnttbl. -- DCS 12/1/94 */ + +int +cfs_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. */ + cfsnc_flush(dcstat); + + for (hash = 0; hash < CFS_CACHESIZE; hash++) { + for (cp = cfs_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) { + if (CTOV(cp)->v_mount == whoIam) { +#ifdef DEBUG + printf("cfs_kill: vp %p, cp %p\n", CTOV(cp), cp); +#endif + count++; + CFSDEBUG(CFS_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 +cfs_flush(dcstat) + enum dc_status dcstat; +{ + int hash; + struct cnode *cp; + + cfs_clstat.ncalls++; + cfs_clstat.reqs[CFS_FLUSH]++; + + cfsnc_flush(dcstat); /* flush files from the name cache */ + + for (hash = 0; hash < CFS_CACHESIZE; hash++) { + for (cp = cfs_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) { + if (!ODD(cp->c_fid.Vnode)) /* only files can be executed */ + cfs_vmflush(cp); + } + } +} + +/* + * As a debugging measure, print out any cnodes that lived through a + * name cache flush. + */ +void +cfs_testflush(void) +{ + int hash; + struct cnode *cp; + + for (hash = 0; hash < CFS_CACHESIZE; hash++) { + for (cp = cfs_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 +cfs_unmounting(whoIam) + struct mount *whoIam; +{ + int hash; + struct cnode *cp; + + for (hash = 0; hash < CFS_CACHESIZE; hash++) { + for (cp = cfs_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) { + if (CTOV(cp)->v_mount == whoIam) { + if (cp->c_flags & (C_LOCKED|C_WANTED)) { + printf("cfs_unmounting: Unlocking %p\n", cp); + cp->c_flags &= ~(C_LOCKED|C_WANTED); + wakeup((caddr_t) cp); + } + cp->c_flags |= C_UNMOUNTING; + } + } + } +} + +#ifdef DEBUG +cfs_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; + } + } +} + +int +cfs_cacheprint(whoIam) + struct mount *whoIam; +{ + int hash; + struct cnode *cp; + int count = 0; + + printf("cfs_cacheprint: cfs_ctlvp %p, cp %p", cfs_ctlvp, VTOC(cfs_ctlvp)); + cfsnc_name(cfs_ctlvp); + printf("\n"); + + for (hash = 0; hash < CFS_CACHESIZE; hash++) { + for (cp = cfs_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) { + if (CTOV(cp)->v_mount == whoIam) { + printf("cfs_cacheprint: vp %p, cp %p", CTOV(cp), cp); + cfsnc_name(cp); + printf("\n"); + count++; + } + } + } + printf("cfs_cacheprint: count %d\n", count); +} +#endif + +/* + * There are 6 cases where invalidations occur. The semantics of each + * is listed here. + * + * CFS_FLUSH -- flush all entries from the name cache and the cnode cache. + * CFS_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. + * CFS_ZAPDIR -- flush the attributes for the dir from its cnode. + * Zap all children of this directory from the namecache. + * CFS_ZAPFILE -- flush the attributes for a file. + * + * The fifth is a result of Venus detecting an inconsistent file. + * CFS_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. + * + * CFS_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 CFS_FLUSH : { + + cfs_flush(IS_DOWNCALL); + + CFSDEBUG(CFS_FLUSH,cfs_testflush();) /* print remaining cnodes */ + return(0); + } + + case CFS_PURGEUSER : { + cfs_clstat.ncalls++; + cfs_clstat.reqs[CFS_PURGEUSER]++; + + /* XXX - need to prevent fsync's */ + cfsnc_purge_user(out->cfs_purgeuser.cred.cr_uid, IS_DOWNCALL); + return(0); + } + + case CFS_ZAPFILE : { + struct cnode *cp; + + error = 0; + cfs_clstat.ncalls++; + cfs_clstat.reqs[CFS_ZAPFILE]++; + + cp = cfs_find(&out->cfs_zapfile.CodaFid); + if (cp != NULL) { + vref(CTOV(cp)); + + cp->c_flags &= ~C_VATTR; + if (CTOV(cp)->v_flag & VTEXT) + error = cfs_vmflush(cp); + CFSDEBUG(CFS_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 CFS_ZAPDIR : { + struct cnode *cp; + + cfs_clstat.ncalls++; + cfs_clstat.reqs[CFS_ZAPDIR]++; + + cp = cfs_find(&out->cfs_zapdir.CodaFid); + if (cp != NULL) { + vref(CTOV(cp)); + + cp->c_flags &= ~C_VATTR; + cfsnc_zapParentfid(&out->cfs_zapdir.CodaFid, IS_DOWNCALL); + + CFSDEBUG(CFS_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 CFS_ZAPVNODE : { + cfs_clstat.ncalls++; + cfs_clstat.reqs[CFS_ZAPVNODE]++; + + myprintf(("CFS_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. + */ + /* cfsnc_zapvnode(&out->cfs_zapvnode.VFid, &out->cfs_zapvnode.cred, + IS_DOWNCALL); */ + return(0); + } + + case CFS_PURGEFID : { + struct cnode *cp; + + error = 0; + cfs_clstat.ncalls++; + cfs_clstat.reqs[CFS_PURGEFID]++; + + cp = cfs_find(&out->cfs_purgefid.CodaFid); + if (cp != NULL) { + vref(CTOV(cp)); + if (ODD(out->cfs_purgefid.CodaFid.Vnode)) { /* Vnode is a directory */ + cfsnc_zapParentfid(&out->cfs_purgefid.CodaFid, + IS_DOWNCALL); + } + cp->c_flags &= ~C_VATTR; + cfsnc_zapfid(&out->cfs_purgefid.CodaFid, IS_DOWNCALL); + if (!(ODD(out->cfs_purgefid.CodaFid.Vnode)) + && (CTOV(cp)->v_flag & VTEXT)) { + + error = cfs_vmflush(cp); + } + CFSDEBUG(CFS_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 CFS_REPLACE : { + struct cnode *cp = NULL; + + cfs_clstat.ncalls++; + cfs_clstat.reqs[CFS_REPLACE]++; + + cp = cfs_find(&out->cfs_replace.OldFid); + if (cp != NULL) { + /* remove the cnode from the hash table, replace the fid, and reinsert */ + vref(CTOV(cp)); + cfs_unsave(cp); + cp->c_fid = out->cfs_replace.NewFid; + cfs_save(cp); + + CFSDEBUG(CFS_REPLACE, myprintf(("replace: oldfid = (%lx.%lx.%lx), newfid = (%lx.%lx.%lx), cp = %p\n", + out->cfs_replace.OldFid.Volume, + out->cfs_replace.OldFid.Vnode, + out->cfs_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); + } +} + +/* cfs_grab_vnode: lives in either cfs_mach.c or cfs_nbsd.c */ + +int +cfs_vmflush(cp) + struct cnode *cp; +{ +#if 0 + /* old code */ + /* Unset so that page_read doesn't try to use + (possibly) invalid cache file. */ + cp->c_device = 0; + cp->c_inode = 0; + + return(inode_uncache_try(VTOI(CTOV(cp))) ? 0 : ETXTBSY); +#else /* __NetBSD__ || __FreeBSD__ */ + return 0; +#endif /* __NetBSD__ || __FreeBSD__ */ +} + + +/* + * kernel-internal debugging switches + */ + +void cfs_debugon(void) +{ + cfsdebug = -1; + cfsnc_debug = -1; + cfs_vnop_print_entry = 1; + cfs_psdev_print_entry = 1; + cfs_vfsop_print_entry = 1; +} + +void cfs_debugoff(void) +{ + cfsdebug = 0; + cfsnc_debug = 0; + cfs_vnop_print_entry = 0; + cfs_psdev_print_entry = 0; + cfs_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 + * ... + */ + + +#endif /* NVCFS */ diff --git a/sys/fs/coda/coda_subr.h b/sys/fs/coda/coda_subr.h new file mode 100644 index 0000000..cf983d4 --- /dev/null +++ b/sys/fs/coda/coda_subr.h @@ -0,0 +1,45 @@ +/* + + 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. +*/ + +/* $Header: /afs/cs/project/coda-src/cvs/coda/kernel-src/vfs/freebsd/cfs/cfs_subr.h,v 1.4 1998/08/18 17:05:16 rvb Exp $ */ + +struct cnode *cfs_alloc(void); +void cfs_free(struct cnode *cp); +struct cnode *cfs_find(ViceFid *fid); +void cfs_flush(enum dc_status dcstat); +void cfs_testflush(void); +int cfs_checkunmounting(struct mount *mp); +int cfs_cacheprint(struct mount *whoIam); +void cfs_debugon(void); +void cfs_debugoff(void); +int cfs_kill(struct mount *whoIam, enum dc_status dcstat); +void cfs_save(struct cnode *cp); +void cfs_unsave(struct cnode *cp); + + diff --git a/sys/fs/coda/coda_venus.c b/sys/fs/coda/coda_venus.c new file mode 100644 index 0000000..8767914 --- /dev/null +++ b/sys/fs/coda/coda_venus.c @@ -0,0 +1,654 @@ +/* + + 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. +*/ + +/* $Header: /afs/cs/project/coda-src/cvs/coda/kernel-src/vfs/freebsd/cfs/cfs_venus.c,v 1.11 1998/08/28 18:12:20 rvb Exp $ */ + +#include +#include +#include +#include +#include +#ifdef __FreeBSD_version +#include +#else +#include +#endif +/* for CNV_OFLAGS below */ +#include + +#include +#include +#include +#include + +#define DECL_NO_IN(name) \ + struct cfs_in_hdr *inp; \ + struct name ## _out *outp; \ + int name ## _size = sizeof (struct cfs_in_hdr); \ + int Isize = sizeof (struct cfs_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 cfs_out_hdr *outp; \ + int name ## _size = sizeof (struct name ## _in); \ + int Isize = sizeof (struct name ## _in); \ + int Osize = sizeof (struct cfs_out_hdr); \ + int error + +#define ALLOC_NO_IN(name) \ + if (Osize > name ## _size) \ + name ## _size = Osize; \ + CFS_ALLOC(inp, struct cfs_in_hdr *, name ## _size);\ + outp = (struct name ## _out *) inp + +#define ALLOC(name) \ + if (Osize > name ## _size) \ + name ## _size = Osize; \ + CFS_ALLOC(inp, struct name ## _in *, name ## _size);\ + outp = (struct name ## _out *) inp + +#define ALLOC_NO_OUT(name) \ + if (Osize > name ## _size) \ + name ## _size = Osize; \ + CFS_ALLOC(inp, struct name ## _in *, name ## _size);\ + outp = (struct cfs_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; \ + } 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(cfs_root); /* sets Isize & Osize */ + ALLOC_NO_IN(cfs_root); /* sets inp & outp */ + + /* send the open to venus. */ + INIT_IN(inp, CFS_ROOT, cred, p); + + error = cfscall(mdp, Isize, &Osize, (char *)inp); + if (!error) + *VFid = outp->VFid; + + CFS_FREE(inp, cfs_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(cfs_open); /* sets Isize & Osize */ + ALLOC(cfs_open); /* sets inp & outp */ + + /* send the open to venus. */ + INIT_IN(&inp->ih, CFS_OPEN, cred, p); + inp->VFid = *fid; + CNV_OFLAG(cflag, flag); + inp->flags = cflag; + + error = cfscall(mdp, Isize, &Osize, (char *)inp); + if (!error) { + *dev = outp->dev; + *inode = outp->inode; + } + + CFS_FREE(inp, cfs_open_size); + return error; +} + +int +venus_close(void *mdp, ViceFid *fid, int flag, + struct ucred *cred, struct proc *p) +{ + int cflag; + DECL_NO_OUT(cfs_close); /* sets Isize & Osize */ + ALLOC_NO_OUT(cfs_close); /* sets inp & outp */ + + INIT_IN(&inp->ih, CFS_CLOSE, cred, p); + inp->VFid = *fid; + CNV_OFLAG(cflag, flag); + inp->flags = cflag; + + error = cfscall(mdp, Isize, &Osize, (char *)inp); + + CFS_FREE(inp, cfs_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(cfs_ioctl); /* sets Isize & Osize */ + struct PioctlData *iap = (struct PioctlData *)data; + int tmp; + + cfs_ioctl_size = VC_MAXMSGSIZE; + ALLOC(cfs_ioctl); /* sets inp & outp */ + + INIT_IN(&inp->ih, CFS_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 cfs_ioctl_in)); + + error = copyin(iap->vi.in, (char*)inp + (int)inp->data, + iap->vi.in_size); + if (error) { + CFS_FREE(inp, cfs_ioctl_size); + return(error); + } + + Osize = VC_MAXMSGSIZE; + error = cfscall(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); + } + } + + CFS_FREE(inp, cfs_ioctl_size); + return error; +} + +int +venus_getattr(void *mdp, ViceFid *fid, + struct ucred *cred, struct proc *p, +/*out*/ struct vattr *vap) +{ + DECL(cfs_getattr); /* sets Isize & Osize */ + ALLOC(cfs_getattr); /* sets inp & outp */ + + /* send the open to venus. */ + INIT_IN(&inp->ih, CFS_GETATTR, cred, p); + inp->VFid = *fid; + + error = cfscall(mdp, Isize, &Osize, (char *)inp); + if (!error) { + CNV_VV2V_ATTR(vap, &outp->attr); + } + + CFS_FREE(inp, cfs_getattr_size); + return error; +} + +int +venus_setattr(void *mdp, ViceFid *fid, struct vattr *vap, + struct ucred *cred, struct proc *p) +{ + DECL_NO_OUT(cfs_setattr); /* sets Isize & Osize */ + ALLOC_NO_OUT(cfs_setattr); /* sets inp & outp */ + + /* send the open to venus. */ + INIT_IN(&inp->ih, CFS_SETATTR, cred, p); + inp->VFid = *fid; + CNV_V2VV_ATTR(&inp->attr, vap); + + error = cfscall(mdp, Isize, &Osize, (char *)inp); + + CFS_FREE(inp, cfs_setattr_size); + return error; +} + +int +venus_access(void *mdp, ViceFid *fid, int mode, + struct ucred *cred, struct proc *p) +{ + DECL_NO_OUT(cfs_access); /* sets Isize & Osize */ + ALLOC_NO_OUT(cfs_access); /* sets inp & outp */ + + /* send the open to venus. */ + INIT_IN(&inp->ih, CFS_ACCESS, cred, p); + inp->VFid = *fid; +#ifdef NetBSD1_3 + inp->flags = mode; +#else + inp->flags = mode>>6; +#endif + + error = cfscall(mdp, Isize, &Osize, (char *)inp); + + CFS_FREE(inp, cfs_access_size); + return error; +} + +int +venus_readlink(void *mdp, ViceFid *fid, + struct ucred *cred, struct proc *p, +/*out*/ char **str, int *len) +{ + DECL(cfs_readlink); /* sets Isize & Osize */ + cfs_readlink_size += CFS_MAXPATHLEN; + ALLOC(cfs_readlink); /* sets inp & outp */ + + /* send the open to venus. */ + INIT_IN(&inp->ih, CFS_READLINK, cred, p); + inp->VFid = *fid; + + Osize += CFS_MAXPATHLEN; + error = cfscall(mdp, Isize, &Osize, (char *)inp); + if (!error) { + CFS_ALLOC(*str, char *, outp->count); + *len = outp->count; + bcopy((char *)outp + (int)outp->data, *str, *len); + } + + CFS_FREE(inp, cfs_readlink_size); + return error; +} + +int +venus_fsync(void *mdp, ViceFid *fid, + struct ucred *cred, struct proc *p) +{ + DECL_NO_OUT(cfs_fsync); /* sets Isize & Osize */ + ALLOC_NO_OUT(cfs_fsync); /* sets inp & outp */ + + /* send the open to venus. */ + INIT_IN(&inp->ih, CFS_FSYNC, cred, p); + inp->VFid = *fid; + + error = cfscall(mdp, Isize, &Osize, (char *)inp); + + CFS_FREE(inp, cfs_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(cfs_lookup); /* sets Isize & Osize */ + cfs_lookup_size += len + 1; + ALLOC(cfs_lookup); /* sets inp & outp */ + + /* send the open to venus. */ + INIT_IN(&inp->ih, CFS_LOOKUP, cred, p); + inp->VFid = *fid; + + inp->name = Isize; + STRCPY(name, nm, len); /* increments Isize */ + + error = cfscall(mdp, Isize, &Osize, (char *)inp); + if (!error) { + *VFid = outp->VFid; + *vtype = outp->vtype; + } + + CFS_FREE(inp, cfs_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(cfs_create); /* sets Isize & Osize */ + cfs_create_size += len + 1; + ALLOC(cfs_create); /* sets inp & outp */ + + /* send the open to venus. */ + INIT_IN(&inp->ih, CFS_CREATE, cred, p); + inp->VFid = *fid; + inp->excl = exclusive ? C_O_EXCL : 0; +#ifdef NetBSD1_3 + inp->mode = mode<<6; +#else + inp->mode = mode; +#endif + CNV_V2VV_ATTR(&inp->attr, va); + + inp->name = Isize; + STRCPY(name, nm, len); /* increments Isize */ + + error = cfscall(mdp, Isize, &Osize, (char *)inp); + if (!error) { + *VFid = outp->VFid; + CNV_VV2V_ATTR(attr, &outp->attr); + } + + CFS_FREE(inp, cfs_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(cfs_remove); /* sets Isize & Osize */ + cfs_remove_size += len + 1; + ALLOC_NO_OUT(cfs_remove); /* sets inp & outp */ + + /* send the open to venus. */ + INIT_IN(&inp->ih, CFS_REMOVE, cred, p); + inp->VFid = *fid; + + inp->name = Isize; + STRCPY(name, nm, len); /* increments Isize */ + + error = cfscall(mdp, Isize, &Osize, (char *)inp); + + CFS_FREE(inp, cfs_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(cfs_link); /* sets Isize & Osize */ + cfs_link_size += len + 1; + ALLOC_NO_OUT(cfs_link); /* sets inp & outp */ + + /* send the open to venus. */ + INIT_IN(&inp->ih, CFS_LINK, cred, p); + inp->sourceFid = *fid; + inp->destFid = *tfid; + + inp->tname = Isize; + STRCPY(tname, nm, len); /* increments Isize */ + + error = cfscall(mdp, Isize, &Osize, (char *)inp); + + CFS_FREE(inp, cfs_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(cfs_rename); /* sets Isize & Osize */ + cfs_rename_size += len + 1 + tlen + 1; + ALLOC_NO_OUT(cfs_rename); /* sets inp & outp */ + + /* send the open to venus. */ + INIT_IN(&inp->ih, CFS_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 = cfscall(mdp, Isize, &Osize, (char *)inp); + + CFS_FREE(inp, cfs_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(cfs_mkdir); /* sets Isize & Osize */ + cfs_mkdir_size += len + 1; + ALLOC(cfs_mkdir); /* sets inp & outp */ + + /* send the open to venus. */ + INIT_IN(&inp->ih, CFS_MKDIR, cred, p); + inp->VFid = *fid; + CNV_V2VV_ATTR(&inp->attr, va); + + inp->name = Isize; + STRCPY(name, nm, len); /* increments Isize */ + + error = cfscall(mdp, Isize, &Osize, (char *)inp); + if (!error) { + *VFid = outp->VFid; + CNV_VV2V_ATTR(ova, &outp->attr); + } + + CFS_FREE(inp, cfs_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(cfs_rmdir); /* sets Isize & Osize */ + cfs_rmdir_size += len + 1; + ALLOC_NO_OUT(cfs_rmdir); /* sets inp & outp */ + + /* send the open to venus. */ + INIT_IN(&inp->ih, CFS_RMDIR, cred, p); + inp->VFid = *fid; + + inp->name = Isize; + STRCPY(name, nm, len); /* increments Isize */ + + error = cfscall(mdp, Isize, &Osize, (char *)inp); + + CFS_FREE(inp, cfs_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(cfs_symlink); /* sets Isize & Osize */ + cfs_symlink_size += llen + 1 + len + 1; + ALLOC_NO_OUT(cfs_symlink); /* sets inp & outp */ + + /* send the open to venus. */ + INIT_IN(&inp->ih, CFS_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 = cfscall(mdp, Isize, &Osize, (char *)inp); + + CFS_FREE(inp, cfs_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(cfs_readdir); /* sets Isize & Osize */ + cfs_readdir_size = VC_MAXMSGSIZE; + ALLOC(cfs_readdir); /* sets inp & outp */ + + /* send the open to venus. */ + INIT_IN(&inp->ih, CFS_READDIR, cred, p); + inp->VFid = *fid; + inp->count = count; + inp->offset = offset; + + Osize = VC_MAXMSGSIZE; + error = cfscall(mdp, Isize, &Osize, (char *)inp); + if (!error) { + bcopy((char *)outp + (int)outp->data, buffer, outp->size); + *len = outp->size; + } + + CFS_FREE(inp, cfs_readdir_size); + return error; +} + +int +venus_fhtovp(void *mdp, ViceFid *fid, + struct ucred *cred, struct proc *p, +/*out*/ ViceFid *VFid, int *vtype) +{ + DECL(cfs_vget); /* sets Isize & Osize */ + ALLOC(cfs_vget); /* sets inp & outp */ + + /* Send the open to Venus. */ + INIT_IN(&inp->ih, CFS_VGET, cred, p); + inp->VFid = *fid; + + error = cfscall(mdp, Isize, &Osize, (char *)inp); + if (!error) { + *VFid = outp->VFid; + *vtype = outp->vtype; + } + + CFS_FREE(inp, cfs_vget_size); + return error; +} diff --git a/sys/fs/coda/coda_venus.h b/sys/fs/coda/coda_venus.h new file mode 100644 index 0000000..19c95e7 --- /dev/null +++ b/sys/fs/coda/coda_venus.h @@ -0,0 +1,131 @@ +/* + + 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. +*/ + +/* $Header: /afs/cs/project/coda-src/cvs/coda/kernel-src/vfs/freebsd/cfs/cfs_venus.h,v 1.4 1998/08/18 17:05:18 rvb Exp $ */ + +int +venus_root(void *mdp, + struct ucred *cred, struct proc *p, +/*out*/ ViceFid *VFid); + +int +venus_open(void *mdp, ViceFid *fid, int flag, + struct ucred *cred, struct proc *p, +/*out*/ dev_t *dev, ino_t *inode); + +int +venus_close(void *mdp, ViceFid *fid, int flag, + struct ucred *cred, struct proc *p); + +void +venus_read(void); + +void +venus_write(void); + +int +venus_ioctl(void *mdp, ViceFid *fid, + int com, int flag, caddr_t data, + struct ucred *cred, struct proc *p); + +int +venus_getattr(void *mdp, ViceFid *fid, + struct ucred *cred, struct proc *p, +/*out*/ struct vattr *vap); + +int +venus_setattr(void *mdp, ViceFid *fid, struct vattr *vap, + struct ucred *cred, struct proc *p); + +int +venus_access(void *mdp, ViceFid *fid, int mode, + struct ucred *cred, struct proc *p); + +int +venus_readlink(void *mdp, ViceFid *fid, + struct ucred *cred, struct proc *p, +/*out*/ char **str, int *len); + +int +venus_fsync(void *mdp, ViceFid *fid, + struct ucred *cred, struct proc *p); + +int +venus_lookup(void *mdp, ViceFid *fid, + const char *nm, int len, + struct ucred *cred, struct proc *p, +/*out*/ ViceFid *VFid, int *vtype); + +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); + +int +venus_remove(void *mdp, ViceFid *fid, + const char *nm, int len, + struct ucred *cred, struct proc *p); + +int +venus_link(void *mdp, ViceFid *fid, ViceFid *tfid, + const char *nm, int len, + struct ucred *cred, struct proc *p); + +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); + +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); + +int +venus_rmdir(void *mdp, ViceFid *fid, + const char *nm, int len, + struct ucred *cred, struct proc *p); + +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); + +int +venus_readdir(void *mdp, ViceFid *fid, + int count, int offset, + struct ucred *cred, struct proc *p, +/*out*/ char *buffer, int *len); + +int +venus_fhtovp(void *mdp, ViceFid *fid, + struct ucred *cred, struct proc *p, +/*out*/ ViceFid *VFid, int *vtype); diff --git a/sys/fs/coda/coda_vfsops.c b/sys/fs/coda/coda_vfsops.c new file mode 100644 index 0000000..d44533a --- /dev/null +++ b/sys/fs/coda/coda_vfsops.c @@ -0,0 +1,887 @@ +/* + + 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. +*/ + +/* $Header: /afs/cs/project/coda-src/cvs/coda/kernel-src/vfs/freebsd/cfs/cfs_vfsops.c,v 1.11 1998/08/28 18:12:22 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: cfs_vfsops.c,v $ + * Revision 1.11 1998/08/28 18:12:22 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:19 rvb + * Don't use __RCSID now + * + * Revision 1.9 1998/08/18 16:31:44 rvb + * Sync the code for NetBSD -current; test on 1.3 later + * + * Revision 1.8 98/02/24 22:22:48 rvb + * Fixes up mainly to flush iopen and friends + * + * Revision 1.7 98/01/23 11:53:45 rvb + * Bring RVB_CFS1_1 to HEAD + * + * Revision 1.6.2.6 98/01/23 11:21:07 rvb + * Sync with 2.2.5 + * + * Revision 1.6.2.5 98/01/22 13:05:33 rvb + * Move makecfsnode ctlfid later so vfsp is known + * + * Revision 1.6.2.4 97/12/19 14:26:05 rvb + * session id + * + * Revision 1.6.2.3 97/12/16 12:40:11 rvb + * Sync with 1.3 + * + * Revision 1.6.2.2 97/12/10 11:40:25 rvb + * No more ody + * + * Revision 1.6.2.1 97/12/06 17:41:24 rvb + * Sync with peters coda.h + * + * Revision 1.6 97/12/05 10:39:21 rvb + * Read CHANGES + * + * Revision 1.5.14.8 97/11/24 15:44:46 rvb + * Final cfs_venus.c w/o macros, but one locking bug + * + * Revision 1.5.14.7 97/11/21 13:22:03 rvb + * Catch a few cfscalls in cfs_vfsops.c + * + * Revision 1.5.14.6 97/11/20 11:46:48 rvb + * Capture current cfs_venus + * + * Revision 1.5.14.5 97/11/18 10:27:17 rvb + * cfs_nbsd.c is DEAD!!!; integrated into cfs_vf/vnops.c + * cfs_nb_foo and cfs_foo are joined + * + * Revision 1.5.14.4 97/11/13 22:03:01 rvb + * pass2 cfs_NetBSD.h mt + * + * Revision 1.5.14.3 97/11/12 12:09:40 rvb + * reorg pass1 + * + * Revision 1.5.14.2 97/10/29 16:06:28 rvb + * Kill DYING + * + * Revision 1.5.14.1 1997/10/28 23:10:17 rvb + * >64Meg; venus can be killed! + * + * Revision 1.5 1997/01/13 17:11:07 bnoble + * Coda statfs needs to return something other than -1 for blocks avail. and + * files available for wabi (and other windowsish) programs to install + * there correctly. + * + * Revision 1.4 1996/12/12 22:11:00 bnoble + * Fixed the "downcall invokes venus operation" deadlock in all known cases. + * There may be more + * + * Revision 1.3 1996/11/08 18:06:12 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:57:04 bnoble + * Added support for Coda MiniCache and raw inode calls (final commit) + * + * Revision 1.1.2.1 1995/12/20 01:57:32 bnoble + * Added CFS-specific files + * + * Revision 3.1.1.1 1995/03/04 19:08:02 bnoble + * Branch for NetBSD port revisions + * + * Revision 3.1 1995/03/04 19:08:01 bnoble + * Bump to major revision 3 to prepare for NetBSD port + * + * Revision 2.4 1995/02/17 16:25:22 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.3 94/10/14 09:58:21 dcs + * Made changes 'cause sun4s have braindead compilers + * + * Revision 2.2 94/10/12 16:46:33 dcs + * Cleaned kernel/venus interface by removing XDR junk, plus + * so cleanup to allow this code to be more easily ported. + * + * Revision 1.3 93/05/28 16:24:29 bnoble + * *** empty log message *** + * + * Revision 1.2 92/10/27 17:58:24 lily + * merge kernel/latest and alpha/src/cfs + * + * Revision 2.3 92/09/30 14:16:32 mja + * Added call to cfs_flush to cfs_unmount. + * [90/12/15 dcs] + * + * Added contributors blurb. + * [90/12/13 jjk] + * + * Revision 2.2 90/07/05 11:26:40 mrt + * Created for the Coda File System. + * [90/05/23 dcs] + * + * Revision 1.3 90/05/31 17:01:42 dcs + * Prepare for merge with facilities kernel. + * + * + */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +/* for VN_RDEV */ +#include + +#ifdef __FreeBSD__ +#ifdef __FreeBSD_version +MALLOC_DEFINE(M_CFS, "CFS storage", "Various Coda Structures"); +#endif +#endif + +int cfsdebug = 0; + +int cfs_vfsop_print_entry = 0; +#ifdef __GNUC__ +#define ENTRY \ + if(cfs_vfsop_print_entry) myprintf(("Entered %s\n",__FUNCTION__)) +#else +#define ENTRY +#endif + + +struct vnode *cfs_ctlvp; +struct cfs_mntinfo cfs_mnttbl[NVCFS]; /* indexed by minor device number */ + +/* structure to keep statistics of internally generated/satisfied calls */ + +struct cfs_op_stats cfs_vfsopstats[CFS_VFSOPS_SIZE]; + +#define MARK_ENTRY(op) (cfs_vfsopstats[op].entries++) +#define MARK_INT_SAT(op) (cfs_vfsopstats[op].sat_intrn++) +#define MARK_INT_FAIL(op) (cfs_vfsopstats[op].unsat_intrn++) +#define MRAK_INT_GEN(op) (cfs_vfsopstats[op].gen_intrn++) + +extern int cfsnc_initialized; /* Set if cache has been initialized */ +extern int vc_nb_open __P((dev_t, int, int, struct proc *)); +#ifdef __NetBSD__ +extern struct cdevsw cdevsw[]; /* For sanity check in cfs_mount */ +#endif +/* NetBSD interface to statfs */ + +#if defined(__NetBSD__) && defined(NetBSD1_3) && (NetBSD1_3 >= 5) +extern struct vnodeopv_desc cfs_vnodeop_opv_desc; + +struct vnodeopv_desc *cfs_vnodeopv_descs[] = { + &cfs_vnodeop_opv_desc, + NULL, +}; + +struct vfsops cfs_vfsops = { + MOUNT_CFS, + cfs_mount, + cfs_start, + cfs_unmount, + cfs_root, + cfs_quotactl, + cfs_nb_statfs, + cfs_sync, + cfs_vget, + (int (*) (struct mount *, struct fid *, struct mbuf *, struct vnode **, + int *, struct ucred **)) + eopnotsupp, + (int (*) (struct vnode *, struct fid *)) eopnotsupp, + cfs_init, +#if (NetBSD1_3 >= 7) + cfs_sysctl, +#endif + (int (*)(void)) eopnotsupp, + cfs_vnodeopv_descs, + 0 +}; +#elif defined(__NetBSD__) +struct vfsops cfs_vfsops = { + MOUNT_CFS, + cfs_mount, + cfs_start, + cfs_unmount, + cfs_root, + cfs_quotactl, + cfs_nb_statfs, + cfs_sync, + cfs_vget, + (int (*) (struct mount *, struct fid *, struct mbuf *, struct vnode **, + int *, struct ucred **)) + eopnotsupp, + (int (*) (struct vnode *, struct fid *)) eopnotsupp, + cfs_init, +#ifdef NetBSD1_3 + (int (*)(void)) eopnotsupp, +#endif + 0 +}; + +#elif defined(__FreeBSD__) +#ifdef __FreeBSD_version +struct vfsops cfs_vfsops = { + cfs_mount, + cfs_start, + cfs_unmount, + cfs_root, + cfs_quotactl, + cfs_nb_statfs, + cfs_sync, + cfs_vget, + (int (*) (struct mount *, struct fid *, struct sockaddr *, struct vnode **, + int *, struct ucred **)) + eopnotsupp, + (int (*) (struct vnode *, struct fid *)) eopnotsupp, + cfs_init, +}; + +#else +struct vfsops cfs_vfsops = { + cfs_mount, + cfs_start, + cfs_unmount, + cfs_root, + cfs_quotactl, + cfs_nb_statfs, + cfs_sync, + cfs_vget, + (int (*) (struct mount *, struct fid *, struct mbuf *, struct vnode **, + int *, struct ucred **)) + eopnotsupp, + (int (*) (struct vnode *, struct fid *)) eopnotsupp, + cfs_init, +}; + +#endif + + +#include +VFS_SET(cfs_vfsops, cfs, MOUNT_CFS, VFCF_NETWORK); +#endif + +int +cfs_vfsopstats_init(void) +{ + register int i; + + for (i=0;ini_vp; + + if (error) { + MARK_INT_FAIL(CFS_MOUNT_STATS); + return (error); + } + if (dvp->v_type != VCHR) { + MARK_INT_FAIL(CFS_MOUNT_STATS); + vrele(dvp); + return(ENXIO); + } + dev = dvp->v_specinfo->si_rdev; + vrele(dvp); + if (major(dev) >= nchrdev || major(dev) < 0) { + MARK_INT_FAIL(CFS_MOUNT_STATS); + return(ENXIO); + } + + /* + * See if the device table matches our expectations. + */ +#ifdef __NetBSD__ + if (cdevsw[major(dev)].d_open != vc_nb_open) +#elif defined(__FreeBSD__) + if (cdevsw[major(dev)]->d_open != vc_nb_open) +#endif + { + MARK_INT_FAIL(CFS_MOUNT_STATS); + return(ENXIO); + } + + if (minor(dev) >= NVCFS || minor(dev) < 0) { + MARK_INT_FAIL(CFS_MOUNT_STATS); + return(ENXIO); + } + + /* + * Initialize the mount record and link it to the vfs struct + */ + mi = &cfs_mnttbl[minor(dev)]; + + if (!VC_OPEN(&mi->mi_vcomm)) { + MARK_INT_FAIL(CFS_MOUNT_STATS); + return(ENODEV); + } + + /* No initialization (here) of mi_vcomm! */ + vfsp->mnt_data = (qaddr_t)mi; +#ifdef __NetBSD__ + vfsp->mnt_stat.f_fsid.val[0] = 0; + vfsp->mnt_stat.f_fsid.val[1] = makefstype(MOUNT_CFS); +#elif defined(__FreeBSD__) && defined(__FreeBSD_version) + + vfs_getnewfsid (vfsp); + +#elif defined(__FreeBSD__) + /* Seems a bit overkill, since usualy /coda is the only mount point + * for cfs. + */ + getnewfsid (vfsp, MOUNT_CFS); +#endif + mi->mi_vfsp = vfsp; + + /* + * Make a root vnode to placate the Vnode interface, but don't + * actually make the CFS_ROOT call to venus until the first call + * to cfs_root in case a server is down while venus is starting. + */ + rootfid.Volume = 0; + rootfid.Vnode = 0; + rootfid.Unique = 0; + cp = makecfsnode(&rootfid, vfsp, VDIR); + rootvp = CTOV(cp); + rootvp->v_flag |= VROOT; + + ctlfid.Volume = CTL_VOL; + ctlfid.Vnode = CTL_VNO; + ctlfid.Unique = CTL_UNI; +/* cp = makecfsnode(&ctlfid, vfsp, VCHR); + The above code seems to cause a loop in the cnode links. + I don't totally understand when it happens, it is caught + when closing down the system. + */ + cp = makecfsnode(&ctlfid, 0, VCHR); + + cfs_ctlvp = CTOV(cp); + + /* Add vfs and rootvp to chain of vfs hanging off mntinfo */ + mi->mi_vfsp = vfsp; + mi->mi_rootvp = rootvp; + + /* set filesystem block size */ + vfsp->mnt_stat.f_bsize = 8192; /* XXX -JJK */ +#ifdef __FreeBSD__ + /* Set f_iosize. XXX -- inamura@isl.ntt.co.jp. + For vnode_pager_haspage() references. The value should be obtained + from underlying UFS. */ + /* Checked UFS. iosize is set as 8192 */ + vfsp->mnt_stat.f_iosize = 8192; +#endif + + /* error is currently guaranteed to be zero, but in case some + code changes... */ + CFSDEBUG(1, + myprintf(("cfs_mount returned %d\n",error));); + if (error) + MARK_INT_FAIL(CFS_MOUNT_STATS); + else + MARK_INT_SAT(CFS_MOUNT_STATS); + + return(error); +} + +int +cfs_start(vfsp, flags, p) + struct mount *vfsp; + int flags; + struct proc *p; +{ + ENTRY; + return (0); +} + +int +cfs_unmount(vfsp, mntflags, p) + struct mount *vfsp; + int mntflags; + struct proc *p; +{ + struct cfs_mntinfo *mi = vftomi(vfsp); + int active, error = 0; + + ENTRY; + MARK_ENTRY(CFS_UMOUNT_STATS); + if (!CFS_MOUNTED(vfsp)) { + MARK_INT_FAIL(CFS_UMOUNT_STATS); + return(EINVAL); + } + + if (mi->mi_vfsp == vfsp) { /* We found the victim */ + if (!IS_UNMOUNTING(VTOC(mi->mi_rootvp))) + return (EBUSY); /* Venus is still running */ + +#ifdef DEBUG + printf("cfs_unmount: ROOT: vp %p, cp %p\n", mi->mi_rootvp, VTOC(mi->mi_rootvp)); +#endif + vrele(mi->mi_rootvp); + +#ifdef NetBSD1_3 + active = cfs_kill(vfsp, NOT_DOWNCALL); + +#if defined(__NetBSD__) && defined(NetBSD1_3) && (NetBSD1_3 >= 7) + if (1) +#else + if ((error = vfs_busy(mi->mi_vfsp)) == 0) +#endif + { + error = vflush(mi->mi_vfsp, NULLVP, FORCECLOSE); + printf("cfs_unmount: active = %d, vflush active %d\n", active, error); + error = 0; + } else { + printf("cfs_unmount: busy\n"); + } +#else /* FreeBSD I guess */ + active = cfs_kill(vfsp, NOT_DOWNCALL); + error = vflush(mi->mi_vfsp, NULLVP, FORCECLOSE); + printf("cfs_unmount: active = %d, vflush active %d\n", active, error); + error = 0; +#endif + /* I'm going to take this out to allow lookups to go through. I'm + * not sure it's important anyway. -- DCS 2/2/94 + */ + /* vfsp->VFS_DATA = NULL; */ + + /* No more vfsp's to hold onto */ + mi->mi_vfsp = NULL; + mi->mi_rootvp = NULL; + + if (error) + MARK_INT_FAIL(CFS_UMOUNT_STATS); + else + MARK_INT_SAT(CFS_UMOUNT_STATS); + + return(error); + } + return (EINVAL); +} + +/* + * find root of cfs + */ +int +cfs_root(vfsp, vpp) + struct mount *vfsp; + struct vnode **vpp; +{ + struct cfs_mntinfo *mi = vftomi(vfsp); + struct vnode **result; + int error; + struct proc *p = curproc; /* XXX - bnoble */ + ViceFid VFid; + + ENTRY; + MARK_ENTRY(CFS_ROOT_STATS); + result = NULL; + + if (vfsp == mi->mi_vfsp) { + if ((VTOC(mi->mi_rootvp)->c_fid.Volume != 0) || + (VTOC(mi->mi_rootvp)->c_fid.Vnode != 0) || + (VTOC(mi->mi_rootvp)->c_fid.Unique != 0)) + { /* Found valid root. */ + *vpp = mi->mi_rootvp; + /* On Mach, this is vref. On NetBSD, VOP_LOCK */ + vref(*vpp); + VOP_X_LOCK(*vpp, LK_EXCLUSIVE); + MARK_INT_SAT(CFS_ROOT_STATS); + return(0); + } + } + + error = venus_root(vftomi(vfsp), p->p_cred->pc_ucred, p, &VFid); + + if (!error) { + /* + * Save the new rootfid in the cnode, and rehash the cnode into the + * cnode hash with the new fid key. + */ + cfs_unsave(VTOC(mi->mi_rootvp)); + VTOC(mi->mi_rootvp)->c_fid = VFid; + cfs_save(VTOC(mi->mi_rootvp)); + + *vpp = mi->mi_rootvp; + vref(*vpp); + VOP_X_LOCK(*vpp, LK_EXCLUSIVE); + MARK_INT_SAT(CFS_ROOT_STATS); + goto exit; + } else if (error == ENODEV) { + /* Gross hack here! */ + /* + * If Venus fails to respond to the CFS_ROOT call, cfscall returns + * ENODEV. Return the uninitialized root vnode to allow vfs + * operations such as unmount to continue. Without this hack, + * there is no way to do an unmount if Venus dies before a + * successful CFS_ROOT call is done. All vnode operations + * will fail. + */ + *vpp = mi->mi_rootvp; + vref(*vpp); + VOP_X_LOCK(*vpp, LK_EXCLUSIVE); + MARK_INT_FAIL(CFS_ROOT_STATS); + error = 0; + goto exit; + } else { + CFSDEBUG( CFS_ROOT, myprintf(("error %d in CFS_ROOT\n", error)); ); + MARK_INT_FAIL(CFS_ROOT_STATS); + + goto exit; + } + exit: + return(error); +} + +int +cfs_quotactl(vfsp, cmd, uid, arg, p) + struct mount *vfsp; + int cmd; + uid_t uid; + caddr_t arg; + struct proc *p; +{ + ENTRY; + return (EOPNOTSUPP); +} + +/* + * Get file system statistics. + */ +int +cfs_nb_statfs(vfsp, sbp, p) + register struct mount *vfsp; + struct statfs *sbp; + struct proc *p; +{ + ENTRY; +/* MARK_ENTRY(CFS_STATFS_STATS); */ + if (!CFS_MOUNTED(vfsp)) { +/* MARK_INT_FAIL(CFS_STATFS_STATS);*/ + return(EINVAL); + } + + bzero(sbp, sizeof(struct statfs)); + /* XXX - what to do about f_flags, others? --bnoble */ + /* Below This is what AFS does + #define NB_SFS_SIZ 0x895440 + */ + /* Note: Normal fs's have a bsize of 0x400 == 1024 */ +#ifdef __NetBSD__ + sbp->f_type = 0; +#elif defined(__FreeBSD__) + sbp->f_type = MOUNT_CFS; +#endif + sbp->f_bsize = 8192; /* XXX */ + sbp->f_iosize = 8192; /* XXX */ +#define NB_SFS_SIZ 0x8AB75D + sbp->f_blocks = NB_SFS_SIZ; + sbp->f_bfree = NB_SFS_SIZ; + sbp->f_bavail = NB_SFS_SIZ; + sbp->f_files = NB_SFS_SIZ; + sbp->f_ffree = NB_SFS_SIZ; + bcopy((caddr_t)&(vfsp->mnt_stat.f_fsid), (caddr_t)&(sbp->f_fsid), sizeof (fsid_t)); +#ifdef __NetBSD__ + strncpy(sbp->f_fstypename, MOUNT_CFS, MFSNAMELEN-1); +#endif + strcpy(sbp->f_mntonname, "/coda"); + strcpy(sbp->f_mntfromname, "CFS"); +/* MARK_INT_SAT(CFS_STATFS_STATS); */ + return(0); +} + +/* + * Flush any pending I/O. + */ +int +cfs_sync(vfsp, waitfor, cred, p) + struct mount *vfsp; + int waitfor; + struct ucred *cred; + struct proc *p; +{ + ENTRY; + MARK_ENTRY(CFS_SYNC_STATS); + MARK_INT_SAT(CFS_SYNC_STATS); + return(0); +} + +int +cfs_vget(vfsp, ino, vpp) + struct mount *vfsp; + ino_t ino; + struct vnode **vpp; +{ + ENTRY; + return (EOPNOTSUPP); +} + +/* + * fhtovp is now what vget used to be in 4.3-derived systems. For + * some silly reason, vget is now keyed by a 32 bit ino_t, rather than + * a type-specific fid. + */ +int +cfs_fhtovp(vfsp, fhp, nam, vpp, exflagsp, creadanonp) + register struct mount *vfsp; + struct fid *fhp; + struct mbuf *nam; + struct vnode **vpp; + int *exflagsp; + struct ucred **creadanonp; +{ + struct cfid *cfid = (struct cfid *)fhp; + struct cnode *cp = 0; + int error; + struct proc *p = curproc; /* XXX -mach */ + ViceFid VFid; + int vtype; + + ENTRY; + + MARK_ENTRY(CFS_VGET_STATS); + /* Check for vget of control object. */ + if (IS_CTL_FID(&cfid->cfid_fid)) { + *vpp = cfs_ctlvp; + vref(cfs_ctlvp); + MARK_INT_SAT(CFS_VGET_STATS); + return(0); + } + + error = venus_fhtovp(vftomi(vfsp), &cfid->cfid_fid, p->p_cred->pc_ucred, p, &VFid, &vtype); + + if (error) { + CFSDEBUG(CFS_VGET, myprintf(("vget error %d\n",error));) + *vpp = (struct vnode *)0; + } else { + CFSDEBUG(CFS_VGET, + myprintf(("vget: vol %lx vno %lx uni %lx type %d result %d\n", + VFid.Volume, VFid.Vnode, VFid.Unique, vtype, error)); ) + + cp = makecfsnode(&VFid, vfsp, vtype); + *vpp = CTOV(cp); + } + return(error); +} + +int +cfs_vptofh(vnp, fidp) + struct vnode *vnp; + struct fid *fidp; +{ + ENTRY; + return (EOPNOTSUPP); +} + +#ifdef __NetBSD__ +void +cfs_init(void) +{ + ENTRY; +} +#elif defined(__FreeBSD__) +#ifdef __FreeBSD_version +int +cfs_init(struct vfsconf *vfsp) +{ + ENTRY; + return 0; +} +#else +int +cfs_init(void) +{ + ENTRY; + return 0; +} +#endif +#endif + +#if defined(__NetBSD__) && defined(NetBSD1_3) && (NetBSD1_3 >= 7) +int +cfs_sysctl(name, namelen, oldp, oldlp, newp, newl, p) + int *name; + u_int namelen; + void *oldp; + size_t *oldlp; + void *newp; + size_t newl; + struct proc *p; +{ + + /* all sysctl names at this level are terminal */ + if (namelen != 1) + return (ENOTDIR); /* overloaded */ + + switch (name[0]) { +/* + case FFS_CLUSTERREAD: + return (sysctl_int(oldp, oldlp, newp, newl, &doclusterread)); + */ + default: + return (EOPNOTSUPP); + } + /* NOTREACHED */ +} +#endif + +/* + * To allow for greater ease of use, some vnodes may be orphaned when + * Venus dies. Certain operations should still be allowed to go + * through, but without propagating ophan-ness. So this function will + * get a new vnode for the file from the current run of Venus. */ + +int +getNewVnode(vpp) + struct vnode **vpp; +{ + struct cfid cfid; + struct cfs_mntinfo *mi = vftomi((*vpp)->v_mount); + + ENTRY; + + cfid.cfid_len = (short)sizeof(ViceFid); + cfid.cfid_fid = VTOC(*vpp)->c_fid; /* Structure assignment. */ + /* XXX ? */ + + /* We're guessing that if set, the 1st element on the list is a + * valid vnode to use. If not, return ENODEV as venus is dead. + */ + if (mi->mi_vfsp == NULL) + return ENODEV; + + return cfs_fhtovp(mi->mi_vfsp, (struct fid*)&cfid, NULL, vpp, + NULL, NULL); +} + +#include +#include +/* get the mount structure corresponding to a given device. Assume + * device corresponds to a UFS. Return NULL if no device is found. + */ +struct mount *devtomp(dev) + dev_t dev; +{ + struct mount *mp, *nmp; + + for (mp = mountlist.cqh_first; mp != (void*)&mountlist; mp = nmp) { + nmp = mp->mnt_list.cqe_next; + if ( +#ifdef __NetBSD__ + (!strcmp(mp->mnt_op->vfs_name, MOUNT_UFS)) && +#endif + ((VFSTOUFS(mp))->um_dev == (dev_t) dev)) { + /* mount corresponds to UFS and the device matches one we want */ + return(mp); + } + } + /* mount structure wasn't found */ + return(NULL); +} diff --git a/sys/fs/coda/coda_vfsops.h b/sys/fs/coda/coda_vfsops.h new file mode 100644 index 0000000..9f8e777 --- /dev/null +++ b/sys/fs/coda/coda_vfsops.h @@ -0,0 +1,78 @@ +/* + + 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. +*/ + +/* $Header: /afs/cs/project/coda-src/cvs/coda/kernel-src/vfs/freebsd/cfs/cfs_vfsops.h,v 1.9 1998/08/28 18:12:22 rvb Exp $ */ + +/* + * cfid structure: + * This overlays the fid structure (see vfs.h) + * Only used below and will probably go away. + */ + +struct cfid { + u_short cfid_len; + u_short padding; + ViceFid cfid_fid; +}; + + +struct mount; + +int cfs_vfsopstats_init(void); +#ifdef NetBSD1_3 +int cfs_mount(struct mount *, const char *, void *, struct nameidata *, + struct proc *); +#else +int cfs_mount(struct mount *, char *, caddr_t, struct nameidata *, + struct proc *); +#endif +int cfs_start(struct mount *, int, struct proc *); +int cfs_unmount(struct mount *, int, struct proc *); +int cfs_root(struct mount *, struct vnode **); +int cfs_quotactl(struct mount *, int, uid_t, caddr_t, struct proc *); +int cfs_nb_statfs(struct mount *, struct statfs *, struct proc *); +int cfs_sync(struct mount *, int, struct ucred *, struct proc *); +int cfs_vget(struct mount *, ino_t, struct vnode **); +int cfs_fhtovp(struct mount *, struct fid *, struct mbuf *, struct vnode **, + int *, struct ucred **); +int cfs_vptofh(struct vnode *, struct fid *); +#ifdef __NetBSD__ +void cfs_init(void); +#elif defined(__FreeBSD__) +#ifdef __FreeBSD_version +int cfs_init(struct vfsconf *vfsp); +#else +int cfs_init(void); +#endif +#endif +#if defined(__NetBSD__) && defined(NetBSD1_3) && (NetBSD1_3 >= 7) +int cfs_sysctl(int *, u_int, void *, size_t *, void *, size_t, + struct proc *); +#endif +int getNewVnode(struct vnode **vpp); diff --git a/sys/fs/coda/coda_vnops.c b/sys/fs/coda/coda_vnops.c new file mode 100644 index 0000000..69197d7 --- /dev/null +++ b/sys/fs/coda/coda_vnops.c @@ -0,0 +1,2802 @@ +/* + + 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. +*/ + +/* $Header: /afs/cs/project/coda-src/cvs/coda/kernel-src/vfs/freebsd/cfs/cfs_vnodeops.c,v 1.12 1998/08/28 18:28:00 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: cfs_vnodeops.c,v $ + * Revision 1.12 1998/08/28 18:28:00 rvb + * NetBSD -current is stricter! + * + * Revision 1.11 1998/08/28 18:12:23 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:21 rvb + * Don't use __RCSID now + * + * Revision 1.9 1998/08/18 16:31:46 rvb + * Sync the code for NetBSD -current; test on 1.3 later + * + * Revision 1.8 98/02/24 22:22:50 rvb + * Fixes up mainly to flush iopen and friends + * + * Revision 1.7 98/01/31 20:53:15 rvb + * First version that works on FreeBSD 2.2.5 + * + * Revision 1.6 98/01/23 11:53:47 rvb + * Bring RVB_CFS1_1 to HEAD + * + * Revision 1.5.2.8 98/01/23 11:21:11 rvb + * Sync with 2.2.5 + * + * Revision 1.5.2.7 97/12/19 14:26:08 rvb + * session id + * + * Revision 1.5.2.6 97/12/16 22:01:34 rvb + * Oops add cfs_subr.h cfs_venus.h; sync with peter + * + * Revision 1.5.2.5 97/12/16 12:40:14 rvb + * Sync with 1.3 + * + * Revision 1.5.2.4 97/12/10 14:08:31 rvb + * Fix O_ flags; check result in cfscall + * + * Revision 1.5.2.3 97/12/10 11:40:27 rvb + * No more ody + * + * Revision 1.5.2.2 97/12/09 16:07:15 rvb + * Sync with vfs/include/coda.h + * + * Revision 1.5.2.1 97/12/06 17:41:25 rvb + * Sync with peters coda.h + * + * Revision 1.5 97/12/05 10:39:23 rvb + * Read CHANGES + * + * Revision 1.4.14.10 97/11/25 08:08:48 rvb + * cfs_venus ... done; until cred/vattr change + * + * Revision 1.4.14.9 97/11/24 15:44:48 rvb + * Final cfs_venus.c w/o macros, but one locking bug + * + * Revision 1.4.14.8 97/11/21 11:28:04 rvb + * cfs_venus.c is done: first pass + * + * Revision 1.4.14.7 97/11/20 11:46:51 rvb + * Capture current cfs_venus + * + * Revision 1.4.14.6 97/11/18 10:27:19 rvb + * cfs_nbsd.c is DEAD!!!; integrated into cfs_vf/vnops.c + * cfs_nb_foo and cfs_foo are joined + * + * Revision 1.4.14.5 97/11/13 22:03:03 rvb + * pass2 cfs_NetBSD.h mt + * + * Revision 1.4.14.4 97/11/12 12:09:42 rvb + * reorg pass1 + * + * Revision 1.4.14.3 97/11/06 21:03:28 rvb + * don't include headers in headers + * + * Revision 1.4.14.2 97/10/29 16:06:30 rvb + * Kill DYING + * + * Revision 1.4.14.1 1997/10/28 23:10:18 rvb + * >64Meg; venus can be killed! + * + * Revision 1.4 1997/02/20 13:54:50 lily + * check for NULL return from cfsnc_lookup before CTOV + * + * Revision 1.3 1996/12/12 22:11:02 bnoble + * Fixed the "downcall invokes venus operation" deadlock in all known cases. + * There may be more + * + * Revision 1.2 1996/01/02 16:57:07 bnoble + * Added support for Coda MiniCache and raw inode calls (final commit) + * + * Revision 1.1.2.1 1995/12/20 01:57:34 bnoble + * Added CFS-specific files + * + * Revision 3.1.1.1 1995/03/04 19:08:06 bnoble + * Branch for NetBSD port revisions + * + * Revision 3.1 1995/03/04 19:08:04 bnoble + * Bump to major revision 3 to prepare for NetBSD port + * + * Revision 2.6 1995/02/17 16:25:26 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 20:29:27 dcs + * Small bug in remove dealing with hard links and link counts was fixed. + * + * Revision 2.4 94/10/14 09:58:42 dcs + * Made changes 'cause sun4s have braindead compilers + * + * Revision 2.3 94/10/12 16:46:37 dcs + * Cleaned kernel/venus interface by removing XDR junk, plus + * so cleanup to allow this code to be more easily ported. + * + * Revision 2.2 94/09/20 14:12:41 dcs + * Fixed bug in rename when moving a directory. + * + * Revision 2.1 94/07/21 16:25:22 satya + * Conversion to C++ 3.0; start of Coda Release 2.0 + * + * Revision 1.4 93/12/17 01:38:01 luqi + * Changes made for kernel to pass process info to Venus: + * + * (1) in file cfs.h + * add process id and process group id in most of the cfs argument types. + * + * (2) in file cfs_vnodeops.c + * add process info passing in most of the cfs vnode operations. + * + * (3) in file cfs_xdr.c + * expand xdr routines according changes in (1). + * add variable pass_process_info to allow venus for kernel version checking. + * + * Revision 1.3 93/05/28 16:24:33 bnoble + * *** empty log message *** + * + * Revision 1.2 92/10/27 17:58:25 lily + * merge kernel/latest and alpha/src/cfs + * + * Revision 2.4 92/09/30 14:16:37 mja + * Redid buffer allocation so that it does kmem_{alloc,free} for all + * architectures. Zone allocation, previously used on the 386, caused + * panics if it was invoked repeatedly. Stack allocation, previously + * used on all other architectures, tickled some Mach bug that appeared + * with large stack frames. + * [91/02/09 jjk] + * + * Added contributors blurb. + * [90/12/13 jjk] + * + * Revision 2.3 90/07/26 15:50:09 mrt + * Fixed fix to rename to remove .. from moved directories. + * [90/06/28 dcs] + * + * Revision 1.7 90/06/28 16:24:25 dcs + * Fixed bug with moving directories, we weren't flushing .. for the moved directory. + * + * Revision 1.6 90/05/31 17:01:47 dcs + * Prepare for merge with facilities kernel. + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __FreeBSD_version +#include +#else +#include +#endif +#include +#include +#include +#ifdef __NetBSD__ +#include +#endif +#include +#ifdef NetBSD1_3 +#include +#endif + +#ifdef __FreeBSD__ +#include +#include +#ifdef __FreeBSD_version +#include +#endif +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * These flags select various performance enhancements. + */ +int cfs_intercept_rdwr = 1; /* Set to handle read/write in the kernel */ +int cfs_attr_cache = 1; /* Set to cache attributes in the kernel */ +int cfs_symlink_cache = 1; /* Set to cache symbolic link information */ +int cfs_access_cache = 1; /* Set to handle some access checks directly */ + +/* structure to keep track of vfs calls */ + +struct cfs_op_stats cfs_vnodeopstats[CFS_VNODEOPS_SIZE]; + +#define MARK_ENTRY(op) (cfs_vnodeopstats[op].entries++) +#define MARK_INT_SAT(op) (cfs_vnodeopstats[op].sat_intrn++) +#define MARK_INT_FAIL(op) (cfs_vnodeopstats[op].unsat_intrn++) +#define MARK_INT_GEN(op) (cfs_vnodeopstats[op].gen_intrn++) + +/* What we are delaying for in printf */ +int cfs_printf_delay = 0; /* in microseconds */ +int cfs_vnop_print_entry = 0; +static int cfs_lockdebug = 0; + +/* Definition of the vfs operation vector */ + +/* + * Some NetBSD details: + * + * cfs_start is called at the end of the mount syscall. + * cfs_init is called at boot time. + */ + +#ifdef __GNUC__ +#define ENTRY \ + if(cfs_vnop_print_entry) myprintf(("Entered %s\n",__FUNCTION__)) +#else +#define ENTRY +#endif + +/* Definition of the vnode operation vector */ + +struct vnodeopv_entry_desc cfs_vnodeop_entries[] = { + { &vop_default_desc, nbsd_vop_error }, + { &vop_lookup_desc, cfs_lookup }, /* lookup */ + { &vop_create_desc, cfs_create }, /* create */ + { &vop_mknod_desc, nbsd_vop_error }, /* mknod */ + { &vop_open_desc, cfs_open }, /* open */ + { &vop_close_desc, cfs_close }, /* close */ + { &vop_access_desc, cfs_access }, /* access */ + { &vop_getattr_desc, cfs_getattr }, /* getattr */ + { &vop_setattr_desc, cfs_setattr }, /* setattr */ + { &vop_read_desc, cfs_read }, /* read */ + { &vop_write_desc, cfs_write }, /* write */ + { &vop_ioctl_desc, cfs_ioctl }, /* ioctl */ +/* 1.3 { &vop_select_desc, cfs_select }, select */ + { &vop_mmap_desc, nbsd_vop_error }, /* mmap */ + { &vop_fsync_desc, cfs_fsync }, /* fsync */ + { &vop_remove_desc, cfs_remove }, /* remove */ + { &vop_link_desc, cfs_link }, /* link */ + { &vop_rename_desc, cfs_rename }, /* rename */ + { &vop_mkdir_desc, cfs_mkdir }, /* mkdir */ + { &vop_rmdir_desc, cfs_rmdir }, /* rmdir */ + { &vop_symlink_desc, cfs_symlink }, /* symlink */ + { &vop_readdir_desc, cfs_readdir }, /* readdir */ + { &vop_readlink_desc, cfs_readlink }, /* readlink */ + { &vop_abortop_desc, cfs_abortop }, /* abortop */ + { &vop_inactive_desc, cfs_inactive }, /* inactive */ + { &vop_reclaim_desc, cfs_reclaim }, /* reclaim */ + { &vop_lock_desc, cfs_lock }, /* lock */ + { &vop_unlock_desc, cfs_unlock }, /* unlock */ + { &vop_bmap_desc, cfs_bmap }, /* bmap */ + { &vop_strategy_desc, cfs_strategy }, /* strategy */ + { &vop_print_desc, nbsd_vop_error }, /* print */ + { &vop_islocked_desc, cfs_islocked }, /* islocked */ + { &vop_pathconf_desc, nbsd_vop_error }, /* pathconf */ + { &vop_advlock_desc, nbsd_vop_nop }, /* advlock */ + { &vop_bwrite_desc, nbsd_vop_error }, /* bwrite */ + { &vop_lease_desc, nbsd_vop_nop }, /* lease */ + +#ifdef __FreeBSD_version +#else /* FreeBSD stable & NetBSD both */ + { &vop_blkatoff_desc, nbsd_vop_error }, /* blkatoff */ + { &vop_valloc_desc, nbsd_vop_error }, /* valloc */ + { &vop_vfree_desc, nbsd_vop_error }, /* vfree */ + { &vop_truncate_desc, nbsd_vop_error }, /* truncate */ + { &vop_update_desc, nbsd_vop_error }, /* update */ +#endif + + /* NetBSD only */ +#ifdef __NetBSD__ +#ifdef NetBSD1_3 + { &vop_seek_desc, genfs_seek }, /* seek */ +#else + { &vop_seek_desc, nbsd_vop_error }, /* seek */ +#endif +#endif + + /* FreeBSD only */ +#ifdef __FreeBSD__ + +#ifdef __FreeBSD_version + + { &vop_poll_desc, (vop_t *) vop_stdpoll }, + { &vop_getpages_desc, (vop_t *) cfs_fbsd_getpages }, /* pager intf.*/ + { &vop_putpages_desc, (vop_t *) cfs_fbsd_putpages }, /* pager intf.*/ + +#if 0 +#define UFS_BLKATOFF(aa, bb, cc, dd) VFSTOUFS((aa)->v_mount)->um_blkatoff(aa, bb, cc, dd) +#define UFS_VALLOC(aa, bb, cc, dd) VFSTOUFS((aa)->v_mount)->um_valloc(aa, bb, cc, dd) +#define UFS_VFREE(aa, bb, cc) VFSTOUFS((aa)->v_mount)->um_vfree(aa, bb, cc) +#define UFS_TRUNCATE(aa, bb, cc, dd, ee) VFSTOUFS((aa)->v_mount)->um_truncate(aa, bb, cc, dd, ee) +#define UFS_UPDATE(aa, bb, cc, dd) VFSTOUFS((aa)->v_mount)->um_update(aa, bb, cc, dd) + + missing + { &vop_reallocblks_desc, (vop_t *) ufs_missingop }, + { &vop_cachedlookup_desc, (vop_t *) ufs_lookup }, + { &vop_whiteout_desc, (vop_t *) ufs_whiteout }, +#endif + +#else /* FreeBSD stable */ + { &vop_getpages_desc, fbsd_vnotsup }, /* pager intf.*/ + { &vop_putpages_desc, fbsd_vnotsup }, /* pager intf.*/ + { &vop_seek_desc, nbsd_vop_error }, /* seek */ + { &vop_blkatoff_desc, nbsd_vop_error }, /* blkatoff */ + { &vop_valloc_desc, nbsd_vop_error }, /* valloc */ + { &vop_vfree_desc, nbsd_vop_error }, /* vfree */ + { &vop_truncate_desc, nbsd_vop_error }, /* truncate */ + { &vop_update_desc, nbsd_vop_error }, /* update */ +#endif +#endif + { (struct vnodeop_desc*)NULL, (int(*)(void *))NULL } +}; + +#ifdef __NetBSD__ +struct vnodeopv_desc cfs_vnodeop_opv_desc = + { &cfs_vnodeop_p, cfs_vnodeop_entries }; + +#define NAMEI_FREE(a) FREE(a, M_NAMEI) +#endif + +#ifdef __FreeBSD__ +static struct vnodeopv_desc cfs_vnodeop_opv_desc = + { &cfs_vnodeop_p, cfs_vnodeop_entries }; + +#include +VNODEOP_SET(cfs_vnodeop_opv_desc); + +int +fbsd_vnotsup(ap) + void *ap; +{ + return(EOPNOTSUPP); +} + +#ifdef __FreeBSD_version +#include + +#define NAMEI_FREE(a) zfree(namei_zone, a); +#else +#define NAMEI_FREE(a) FREE(a, M_NAMEI) +#endif +#endif + +/* Definitions of NetBSD vnodeop interfaces */ + +/* A generic panic: we were called with something we didn't define yet */ +int +nbsd_vop_error(void *anon) { + struct vnodeop_desc **desc = (struct vnodeop_desc **)anon; + + myprintf(("Vnode operation %s called, but not defined\n", + (*desc)->vdesc_name)); + panic("nbsd_vop_error"); + return 0; +} + +/* A generic do-nothing. For lease_check, advlock */ +int +nbsd_vop_nop(void *anon) { + struct vnodeop_desc **desc = (struct vnodeop_desc **)anon; + + if (cfsdebug) { + myprintf(("Vnode operation %s called, but unsupported\n", + (*desc)->vdesc_name)); + } + return (0); +} + +int +cfs_vnodeopstats_init(void) +{ + register int i; + + for(i=0;ia_vp); + struct cnode *cp = VTOC(*vpp); + int flag = ap->a_mode & (~O_EXCL); + struct ucred *cred = ap->a_cred; + struct proc *p = ap->a_p; +/* locals */ + int error; + struct vnode *vp; + dev_t dev; + ino_t inode; + + MARK_ENTRY(CFS_OPEN_STATS); + + /* Check for open of control file. */ + if (IS_CTL_VP(*vpp)) { + /* XXX */ + /* if (WRITEABLE(flag)) */ + if (flag & (FWRITE | O_TRUNC | O_CREAT | O_EXCL)) { + MARK_INT_FAIL(CFS_OPEN_STATS); + return(EACCES); + } + MARK_INT_SAT(CFS_OPEN_STATS); + return(0); + } + + error = venus_open(vtomi((*vpp)), &cp->c_fid, flag, cred, p, &dev, &inode); + if (error) + return (error); + if (!error) { + CFSDEBUG( CFS_OPEN,myprintf(("open: dev %d inode %d result %d\n", + dev, inode, error)); ) + } + + /* Translate the pair for the cache file into + an inode pointer. */ + error = cfs_grab_vnode(dev, inode, &vp); + if (error) + return (error); + + /* We get the vnode back locked in both Mach and NetBSD. Needs unlocked */ + VOP_X_UNLOCK(vp, 0); + /* Keep a reference until the close comes in. */ + vref(*vpp); + + /* Save the vnode pointer for the cache file. */ + if (cp->c_ovp == NULL) { + cp->c_ovp = vp; + } else { + if (cp->c_ovp != vp) + panic("cfs_open: cp->c_ovp != ITOV(ip)"); + } + cp->c_ocount++; + + /* Flush the attribute cached if writing the file. */ + if (flag & FWRITE) { + cp->c_owrite++; + cp->c_flags &= ~C_VATTR; + } + + /* Save the pair for the cache file to speed + up subsequent page_read's. */ + cp->c_device = dev; + cp->c_inode = inode; + + /* Open the cache file. */ + error = VOP_OPEN(vp, flag, cred, p); +#ifdef __FreeBSD__ + if (error) { + printf("cfs_open: VOP_OPEN on container failed %d\n", error); + return (error); + } + if (vp->v_type == VREG) { + error = vfs_object_create(vp, p, cred, 1); + if (error != 0) { + printf("cfs_open: vfs_object_create() returns %d\n", error); + vput(vp); + } + } +#endif + return(error); +} + +/* + * Close the cache file used for I/O and notify Venus. + */ +int +cfs_close(v) + void *v; +{ +/* true args */ + struct vop_close_args *ap = v; + struct vnode *vp = ap->a_vp; + struct cnode *cp = VTOC(vp); + int flag = ap->a_fflag; + struct ucred *cred = ap->a_cred; + struct proc *p = ap->a_p; +/* locals */ + int error; + + MARK_ENTRY(CFS_CLOSE_STATS); + + /* Check for close of control file. */ + if (IS_CTL_VP(vp)) { + MARK_INT_SAT(CFS_CLOSE_STATS); + return(0); + } + + if (IS_UNMOUNTING(cp)) { + if (cp->c_ovp) { + printf("cfs_close: destroying container ref %d, ufs vp %p of vp %p/cp %p\n", + vp->v_usecount, cp->c_ovp, vp, cp); + vgone(cp->c_ovp); + } else { + printf("cfs_close: NO container vp %p/cp %p\n", vp, cp); + } + return ENODEV; + } else { + VOP_CLOSE(cp->c_ovp, flag, cred, p); /* Do errors matter here? */ + vrele(cp->c_ovp); + } + + if (--cp->c_ocount == 0) + cp->c_ovp = NULL; + + if (flag & FWRITE) /* file was opened for write */ + --cp->c_owrite; + + error = venus_close(vtomi(vp), &cp->c_fid, flag, cred, p); + vrele(CTOV(cp)); + + CFSDEBUG(CFS_CLOSE, myprintf(("close: result %d\n",error)); ) + return(error); +} + +int +cfs_read(v) + void *v; +{ + struct vop_read_args *ap = v; + + ENTRY; + return(cfs_rdwr(ap->a_vp, ap->a_uio, UIO_READ, + ap->a_ioflag, ap->a_cred, ap->a_uio->uio_procp)); +} + +int +cfs_write(v) + void *v; +{ + struct vop_write_args *ap = v; + + ENTRY; + return(cfs_rdwr(ap->a_vp, ap->a_uio, UIO_WRITE, + ap->a_ioflag, ap->a_cred, ap->a_uio->uio_procp)); +} + +int +cfs_rdwr(vp, uiop, rw, ioflag, cred, p) + struct vnode *vp; + struct uio *uiop; + enum uio_rw rw; + int ioflag; + struct ucred *cred; + struct proc *p; +{ +/* upcall decl */ + /* NOTE: container file operation!!! */ +/* locals */ + struct cnode *cp = VTOC(vp); + struct vnode *cfvp = cp->c_ovp; + int igot_internally = 0; + int opened_internally = 0; + int error = 0; + + MARK_ENTRY(CFS_RDWR_STATS); + + CFSDEBUG(CFS_RDWR, myprintf(("cfs_rdwr(%d, %p, %d, %qd, %d)\n", rw, + uiop->uio_iov->iov_base, uiop->uio_resid, + uiop->uio_offset, uiop->uio_segflg)); ) + + /* Check for rdwr of control object. */ + if (IS_CTL_VP(vp)) { + MARK_INT_FAIL(CFS_RDWR_STATS); + return(EINVAL); + } + + /* Redirect the request to UFS. */ + + /* + * If file is not already open this must be a page + * {read,write} request. Iget the cache file's inode + * pointer if we still have its pair. + * Otherwise, we must do an internal open to derive the + * pair. + */ + if (cfvp == NULL) { + /* + * If we're dumping core, do the internal open. Otherwise + * venus won't have the correct size of the core when + * it's completely written. + */ + if (cp->c_inode != 0 && !(p && (p->p_acflag & ACORE))) { + igot_internally = 1; + error = cfs_grab_vnode(cp->c_device, cp->c_inode, &cfvp); + if (error) { + MARK_INT_FAIL(CFS_RDWR_STATS); + return(error); + } + /* + * We get the vnode back locked in both Mach and + * NetBSD. Needs unlocked + */ + VOP_X_UNLOCK(cfvp, 0); + } + else { + opened_internally = 1; + MARK_INT_GEN(CFS_OPEN_STATS); + error = VOP_OPEN(vp, (rw == UIO_READ ? FREAD : FWRITE), + cred, p); +printf("cfs_rdwr: Internally Opening %p\n", vp); +#ifdef __FreeBSD__ + if (error) { + printf("cfs_rdwr: VOP_OPEN on container failed %d\n", error); + return (error); + } + if (vp->v_type == VREG) { + error = vfs_object_create(vp, p, cred, 1); + if (error != 0) { + printf("cfs_rdwr: vfs_object_create() returns %d\n", error); + vput(vp); + } + } +#endif + if (error) { + MARK_INT_FAIL(CFS_RDWR_STATS); + return(error); + } + cfvp = cp->c_ovp; + } + } + + /* Have UFS handle the call. */ + CFSDEBUG(CFS_RDWR, myprintf(("indirect rdwr: fid = (%lx.%lx.%lx), refcnt = %d\n", + cp->c_fid.Volume, cp->c_fid.Vnode, + cp->c_fid.Unique, CTOV(cp)->v_usecount)); ) + + if (rw == UIO_READ) { + error = VOP_READ(cfvp, uiop, ioflag, cred); + } else { + error = VOP_WRITE(cfvp, uiop, ioflag, cred); +#ifdef __FreeBSD__ + /* ufs_write updates the vnode_pager_setsize for the vnode/object */ + { struct vattr attr; + + if (VOP_GETATTR(cfvp, &attr, cred, p) == 0) { + vnode_pager_setsize(vp, attr.va_size); +#ifdef __DEBUG_FreeBSD__ + printf("write: vnode_pager_setsize(%p, %d)\n", vp, attr.va_size); +#endif + } + } +#endif + } + + if (error) + MARK_INT_FAIL(CFS_RDWR_STATS); + else + MARK_INT_SAT(CFS_RDWR_STATS); + + /* Do an internal close if necessary. */ + if (opened_internally) { + MARK_INT_GEN(CFS_CLOSE_STATS); + (void)VOP_CLOSE(vp, (rw == UIO_READ ? FREAD : FWRITE), cred, p); + } + + /* Invalidate cached attributes if writing. */ + if (rw == UIO_WRITE) + cp->c_flags &= ~C_VATTR; + return(error); +} + +int +cfs_ioctl(v) + void *v; +{ +/* true args */ + struct vop_ioctl_args *ap = v; + struct vnode *vp = ap->a_vp; + int com = ap->a_command; + caddr_t data = ap->a_data; + int flag = ap->a_fflag; + struct ucred *cred = ap->a_cred; + struct proc *p = ap->a_p; +/* locals */ + int error; + struct vnode *tvp; + struct nameidata ndp; + struct PioctlData *iap = (struct PioctlData *)data; + + MARK_ENTRY(CFS_IOCTL_STATS); + + CFSDEBUG(CFS_IOCTL, myprintf(("in cfs_ioctl on %s\n", iap->path));) + + /* Don't check for operation on a dying object, for ctlvp it + shouldn't matter */ + + /* Must be control object to succeed. */ + if (!IS_CTL_VP(vp)) { + MARK_INT_FAIL(CFS_IOCTL_STATS); + CFSDEBUG(CFS_IOCTL, myprintf(("cfs_ioctl error: vp != ctlvp"));) + return (EOPNOTSUPP); + } + /* Look up the pathname. */ + + /* Should we use the name cache here? It would get it from + lookupname sooner or later anyway, right? */ + + NDINIT(&ndp, LOOKUP, (iap->follow ? FOLLOW : NOFOLLOW), UIO_USERSPACE, ((caddr_t)iap->path), p); + error = namei(&ndp); + tvp = ndp.ni_vp; + + if (error) { + MARK_INT_FAIL(CFS_IOCTL_STATS); + CFSDEBUG(CFS_IOCTL, myprintf(("cfs_ioctl error: lookup returns %d\n", + error));) + return(error); + } + + /* + * Make sure this is a coda style cnode, but it may be a + * different vfsp + */ + /* XXX: this totally violates the comment about vtagtype in vnode.h */ + if (tvp->v_tag != VT_CFS) { + vrele(tvp); + MARK_INT_FAIL(CFS_IOCTL_STATS); + CFSDEBUG(CFS_IOCTL, + myprintf(("cfs_ioctl error: %s not a coda object\n", + iap->path));) + return(EINVAL); + } + + if (iap->vi.in_size > VC_MAXDATASIZE) { + vrele(tvp); + return(EINVAL); + } + error = venus_ioctl(vtomi(tvp), &((VTOC(tvp))->c_fid), com, flag, data, cred, p); + + if (error) + MARK_INT_FAIL(CFS_IOCTL_STATS); + else + CFSDEBUG(CFS_IOCTL, myprintf(("Ioctl returns %d \n", error)); ) + + vrele(tvp); + return(error); +} + +#if 0 +int +cfs_select(v) + void *v; +{ +/* true args */ + struct vop_select_args *ap = v; + struct vnode *vp = ap->a_vp; + int which = ap->a_which; + struct ucred *cred = ap->a_cred; + struct proc *p = ap->a_p; +/* upcall decl */ +/* locals */ + + MARK_ENTRY(CFS_SELECT_STATS); + + myprintf(("in cfs_select\n")); + MARK_INT_FAIL(CFS_SELECT_STATS); + return (EOPNOTSUPP); +} +#endif + +/* + * To reduce the cost of a user-level venus;we cache attributes in + * the kernel. Each cnode has storage allocated for an attribute. If + * c_vattr is valid, return a reference to it. Otherwise, get the + * attributes from venus and store them in the cnode. There is some + * question if this method is a security leak. But I think that in + * order to make this call, the user must have done a lookup and + * opened the file, and therefore should already have access. + */ +int +cfs_getattr(v) + void *v; +{ +/* true args */ + struct vop_getattr_args *ap = v; + struct vnode *vp = ap->a_vp; + struct cnode *cp = VTOC(vp); + struct vattr *vap = ap->a_vap; + struct ucred *cred = ap->a_cred; + struct proc *p = ap->a_p; +/* locals */ + int error; + struct cnode *scp = NULL; + + MARK_ENTRY(CFS_GETATTR_STATS); + +#if 0 + /* Check for operation on a dying object */ + if (IS_DYING(cp)) { + COMPLAIN_BITTERLY(getattr, cp->c_fid); + scp = cp; /* Save old cp */ + /* If no error, gives a valid vnode with which to work. */ + error = getNewVnode(&vp); + if (error) { + MARK_INT_FAIL(CFS_GETATTR_STATS); + return(error); /* Can't contact dead venus */ + } + cp = VTOC(vp); + } +#endif + +#ifdef __FreeBSD__ + if (IS_UNMOUNTING(cp)) + return ENODEV; +#endif + /* Check for getattr of control object. */ + if (IS_CTL_VP(vp)) { + MARK_INT_FAIL(CFS_GETATTR_STATS); + return(ENOENT); + } + + /* Check to see if the attributes have already been cached */ + if (VALID_VATTR(cp)) { + CFSDEBUG(CFS_GETATTR, { myprintf(("attr cache hit: (%lx.%lx.%lx)\n", + cp->c_fid.Volume, + cp->c_fid.Vnode, + cp->c_fid.Unique));}); + CFSDEBUG(CFS_GETATTR, if (!(cfsdebug & ~CFS_GETATTR)) + print_vattr(&cp->c_vattr); ); + + *vap = cp->c_vattr; + MARK_INT_SAT(CFS_GETATTR_STATS); + if (scp) vrele(vp); + return(0); + } + + error = venus_getattr(vtomi(vp), &cp->c_fid, cred, p, vap); + + if (!error) { + CFSDEBUG(CFS_GETATTR, myprintf(("getattr miss (%lx.%lx.%lx): result %d\n", + cp->c_fid.Volume, + cp->c_fid.Vnode, + cp->c_fid.Unique, + error)); ) + + CFSDEBUG(CFS_GETATTR, if (!(cfsdebug & ~CFS_GETATTR)) + print_vattr(vap); ); + +#ifdef __FreeBSD__ + { int size = vap->va_size; + struct vnode *convp = cp->c_ovp; + if (convp != (struct vnode *)0) { + vnode_pager_setsize(convp, size); +#ifdef __DEBUG_FreeBSD__ + printf("getattr: vnode_pager_setsize(%p, %d)\n", convp, size); +#endif + } + } +#endif + /* If not open for write, store attributes in cnode */ + if ((cp->c_owrite == 0) && (cfs_attr_cache)) { + cp->c_vattr = *vap; + cp->c_flags |= C_VATTR; + } + + } + if (scp) vrele(vp); + return(error); +} + +int +cfs_setattr(v) + void *v; +{ +/* true args */ + struct vop_setattr_args *ap = v; + register struct vnode *vp = ap->a_vp; + struct cnode *cp = VTOC(vp); + register struct vattr *vap = ap->a_vap; + struct ucred *cred = ap->a_cred; + struct proc *p = ap->a_p; +/* locals */ + int error; + + MARK_ENTRY(CFS_SETATTR_STATS); + + /* Check for setattr of control object. */ + if (IS_CTL_VP(vp)) { + MARK_INT_FAIL(CFS_SETATTR_STATS); + return(ENOENT); + } + + if (cfsdebug & CFSDBGMSK(CFS_SETATTR)) { + print_vattr(vap); + } + error = venus_setattr(vtomi(vp), &cp->c_fid, vap, cred, p); + + if (!error) + cp->c_flags &= ~C_VATTR; + +#ifdef __FreeBSD__ + { int size = vap->va_size; + struct vnode *convp = cp->c_ovp; + if (size != VNOVAL && convp != (struct vnode *)0) { + vnode_pager_setsize(convp, size); +#ifdef __DEBUG_FreeBSD__ + printf("setattr: vnode_pager_setsize(%p, %d)\n", convp, size); +#endif + } + } +#endif + CFSDEBUG(CFS_SETATTR, myprintf(("setattr %d\n", error)); ) + return(error); +} + +int +cfs_access(v) + void *v; +{ +/* true args */ + struct vop_access_args *ap = v; + struct vnode *vp = ap->a_vp; + struct cnode *cp = VTOC(vp); + int mode = ap->a_mode; + struct ucred *cred = ap->a_cred; + struct proc *p = ap->a_p; +/* locals */ + int error; + + MARK_ENTRY(CFS_ACCESS_STATS); + + /* Check for access of control object. Only read access is + allowed on it. */ + if (IS_CTL_VP(vp)) { + /* bogus hack - all will be marked as successes */ + MARK_INT_SAT(CFS_ACCESS_STATS); + return(((mode & VREAD) && !(mode & (VWRITE | VEXEC))) + ? 0 : EACCES); + } + + /* + * if the file is a directory, and we are checking exec (eg lookup) + * access, and the file is in the namecache, then the user must have + * lookup access to it. + */ + if (cfs_access_cache) { + if ((vp->v_type == VDIR) && (mode & VEXEC)) { + if (cfsnc_lookup(cp, ".", 1, cred)) { + MARK_INT_SAT(CFS_ACCESS_STATS); + return(0); /* it was in the cache */ + } + } + } + + error = venus_access(vtomi(vp), &cp->c_fid, mode, cred, p); + + return(error); +} + +/* + * CFS abort op, called after namei() when a CREATE/DELETE isn't actually + * done. If a buffer has been saved in anticipation of a cfs_create or + * a cfs_remove, delete it. + */ +/* ARGSUSED */ +int +cfs_abortop(v) + void *v; +{ +/* true args */ + struct vop_abortop_args /* { + struct vnode *a_dvp; + struct componentname *a_cnp; + } */ *ap = v; +/* upcall decl */ +/* locals */ + + if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) + NAMEI_FREE(ap->a_cnp->cn_pnbuf); + return (0); +} + +int +cfs_readlink(v) + void *v; +{ +/* true args */ + struct vop_readlink_args *ap = v; + struct vnode *vp = ap->a_vp; + struct cnode *cp = VTOC(vp); + struct uio *uiop = ap->a_uio; + struct ucred *cred = ap->a_cred; + struct proc *p = ap->a_uio->uio_procp; +/* locals */ + int error; + char *str; + int len; + + MARK_ENTRY(CFS_READLINK_STATS); + + /* Check for readlink of control object. */ + if (IS_CTL_VP(vp)) { + MARK_INT_FAIL(CFS_READLINK_STATS); + return(ENOENT); + } + + if ((cfs_symlink_cache) && (VALID_SYMLINK(cp))) { /* symlink was cached */ + uiop->uio_rw = UIO_READ; + error = uiomove(cp->c_symlink, (int)cp->c_symlen, uiop); + if (error) + MARK_INT_FAIL(CFS_READLINK_STATS); + else + MARK_INT_SAT(CFS_READLINK_STATS); + return(error); + } + + error = venus_readlink(vtomi(vp), &cp->c_fid, cred, p, &str, &len); + + if (!error) { + uiop->uio_rw = UIO_READ; + error = uiomove(str, len, uiop); + + if (cfs_symlink_cache) { + cp->c_symlink = str; + cp->c_symlen = len; + cp->c_flags |= C_SYMLINK; + } else + CFS_FREE(str, len); + } + + CFSDEBUG(CFS_READLINK, myprintf(("in readlink result %d\n",error));) + return(error); +} + +int +cfs_fsync(v) + void *v; +{ +/* true args */ + struct vop_fsync_args *ap = v; + struct vnode *vp = ap->a_vp; + struct cnode *cp = VTOC(vp); + struct ucred *cred = ap->a_cred; + struct proc *p = ap->a_p; +/* locals */ + struct vnode *convp = cp->c_ovp; + int error; + + MARK_ENTRY(CFS_FSYNC_STATS); + + /* Check for fsync on an unmounting object */ + /* The NetBSD kernel, in it's infinite wisdom, can try to fsync + * after an unmount has been initiated. This is a Bad Thing, + * which we have to avoid. Not a legitimate failure for stats. + */ + if (IS_UNMOUNTING(cp)) { + return(ENODEV); + } + + /* Check for fsync of control object. */ + if (IS_CTL_VP(vp)) { + MARK_INT_SAT(CFS_FSYNC_STATS); + return(0); + } + + if (convp) + VOP_FSYNC(convp, cred, MNT_WAIT, p); + +#ifdef __FreeBSD__ + /* + * We see fsyncs with usecount == 1 then usecount == 0. + * For now we ignore them. + */ + /* + if (!vp->v_usecount) { + printf("cfs_fsync on vnode %p with %d usecount. c_flags = %x (%x)\n", + vp, vp->v_usecount, cp->c_flags, cp->c_flags&C_PURGING); + } + */ +#endif + + /* + * We can expect fsync on any vnode at all if venus is pruging it. + * Venus can't very well answer the fsync request, now can it? + * Hopefully, it won't have to, because hopefully, venus preserves + * the (possibly untrue) invariant that it never purges an open + * vnode. Hopefully. + */ + if (cp->c_flags & C_PURGING) { + return(0); + } + +#ifdef __FreeBSD__ + /* needs research */ + return 0; +#endif + error = venus_fsync(vtomi(vp), &cp->c_fid, cred, p); + + CFSDEBUG(CFS_FSYNC, myprintf(("in fsync result %d\n",error)); ); + return(error); +} + +int +cfs_inactive(v) + void *v; +{ + /* XXX - at the moment, inactive doesn't look at cred, and doesn't + have a proc pointer. Oops. */ +/* true args */ + struct vop_inactive_args *ap = v; + struct vnode *vp = ap->a_vp; + struct cnode *cp = VTOC(vp); + struct ucred *cred __attribute__((unused)) = NULL; + struct proc *p __attribute__((unused)) = curproc; +/* upcall decl */ +/* locals */ + + /* We don't need to send inactive to venus - DCS */ + MARK_ENTRY(CFS_INACTIVE_STATS); + + if (IS_CTL_VP(vp)) { + MARK_INT_SAT(CFS_INACTIVE_STATS); + return 0; + } + + CFSDEBUG(CFS_INACTIVE, myprintf(("in inactive, %lx.%lx.%lx. vfsp %p\n", + cp->c_fid.Volume, cp->c_fid.Vnode, + cp->c_fid.Unique, vp->v_mount));) + +#ifdef __DEBUG_FreeBSD__ + if (vp->v_flag & VXLOCK) + printf ("Inactive: Vnode is Locked\n"); +#endif + + /* If an array has been allocated to hold the symlink, deallocate it */ + if ((cfs_symlink_cache) && (VALID_SYMLINK(cp))) { + if (cp->c_symlink == NULL) + panic("cfs_inactive: null symlink pointer in cnode"); + + CFS_FREE(cp->c_symlink, cp->c_symlen); + cp->c_flags &= ~C_SYMLINK; + cp->c_symlen = 0; + } + + /* Remove it from the table so it can't be found. */ + cfs_unsave(cp); + if ((struct cfs_mntinfo *)(vp->v_mount->mnt_data) == NULL) { + myprintf(("Help! vfsp->vfs_data was NULL, but vnode %p wasn't dying\n", vp)); + panic("badness in cfs_inactive\n"); + } + + if (IS_UNMOUNTING(cp)) { +#ifdef DEBUG + printf("cfs_inactive: IS_UNMOUNTING use %d: vp %p, cp %p\n", vp->v_usecount, vp, cp); + if (cp->c_ovp != NULL) + printf("cfs_inactive: cp->ovp != NULL use %d: vp %p, cp %p\n", + vp->v_usecount, vp, cp); +#endif +#ifdef NEW_LOCKMGR + NEW_LOCKMGR(&cp->c_lock, LK_RELEASE, &vp->v_interlock); +#endif + } else { +#ifdef DIAGNOSTIC + if (CTOV(cp)->v_usecount) { + panic("cfs_inactive: nonzero reference count"); + } + if (cp->c_ovp != NULL) { + panic("cfs_inactive: cp->ovp != NULL"); + } +#endif +#ifdef NEW_LOCKMGR + VOP_X_UNLOCK(vp, 0); +#endif + vgone(vp); + } + + MARK_INT_SAT(CFS_INACTIVE_STATS); + return(0); +} + +/* + * Remote file system operations having to do with directory manipulation. + */ + +/* + * It appears that in NetBSD, lookup is supposed to return the vnode locked + */ +int +cfs_lookup(v) + void *v; +{ +/* true args */ + struct vop_lookup_args *ap = v; + struct vnode *dvp = ap->a_dvp; + struct cnode *dcp = VTOC(dvp); + struct vnode **vpp = ap->a_vpp; + /* + * It looks as though ap->a_cnp->ni_cnd->cn_nameptr holds the rest + * of the string to xlate, and that we must try to get at least + * ap->a_cnp->ni_cnd->cn_namelen of those characters to macth. I + * could be wrong. + */ + struct componentname *cnp = ap->a_cnp; + struct ucred *cred = cnp->cn_cred; + struct proc *p = cnp->cn_proc; +/* locals */ + struct cnode *cp; + struct cnode *scp = NULL; + const char *nm = cnp->cn_nameptr; + int len = cnp->cn_namelen; + ViceFid VFid; + int vtype; + int error = 0; + + MARK_ENTRY(CFS_LOOKUP_STATS); + + CFSDEBUG(CFS_LOOKUP, myprintf(("lookup: %s in %lx.%lx.%lx\n", + nm, dcp->c_fid.Volume, + dcp->c_fid.Vnode, dcp->c_fid.Unique));); + +#if 0 + /* Check for operation on a dying object */ + if (IS_DYING(dcp)) { + COMPLAIN_BITTERLY(lookup, dcp->c_fid); + scp = dcp; /* Save old dcp */ + /* If no error, gives a valid vnode with which to work. */ + error = getNewVnode(&dvp); + if (error) { + MARK_INT_FAIL(CFS_LOOKUP_STATS); + return(error); /* Can't contact dead venus */ + } + dcp = VTOC(dvp); + } +#endif + + /* Check for lookup of control object. */ + if (IS_CTL_NAME(dvp, nm, len)) { + *vpp = cfs_ctlvp; + vref(*vpp); + MARK_INT_SAT(CFS_LOOKUP_STATS); + if (scp) vrele(dvp); + goto exit; + } + + if (len+1 > CFS_MAXNAMLEN) { + MARK_INT_FAIL(CFS_LOOKUP_STATS); + CFSDEBUG(CFS_LOOKUP, myprintf(("name too long: lookup, %lx.%lx.%lx(%s)\n", + dcp->c_fid.Volume, dcp->c_fid.Vnode, + dcp->c_fid.Unique, nm));); + *vpp = (struct vnode *)0; + error = EINVAL; + goto exit; + } + /* First try to look the file up in the cfs name cache */ + /* lock the parent vnode? */ + cp = cfsnc_lookup(dcp, nm, len, cred); + if (cp) { + *vpp = CTOV(cp); + vref(*vpp); + CFSDEBUG(CFS_LOOKUP, + myprintf(("lookup result %d vpp %p\n",error,*vpp));) + } else { + + /* The name wasn't cached, so we need to contact Venus */ + error = venus_lookup(vtomi(dvp), &dcp->c_fid, nm, len, cred, p, &VFid, &vtype); + + if (error) { + MARK_INT_FAIL(CFS_LOOKUP_STATS); + CFSDEBUG(CFS_LOOKUP, myprintf(("lookup error on %lx.%lx.%lx(%s)%d\n", + dcp->c_fid.Volume, dcp->c_fid.Vnode, dcp->c_fid.Unique, nm, error));) + *vpp = (struct vnode *)0; + } else { + MARK_INT_SAT(CFS_LOOKUP_STATS); + CFSDEBUG(CFS_LOOKUP, + myprintf(("lookup: vol %lx vno %lx uni %lx type %o result %d\n", + VFid.Volume, VFid.Vnode, VFid.Unique, vtype, + error)); ) + + cp = makecfsnode(&VFid, dvp->v_mount, vtype); + *vpp = CTOV(cp); + + /* enter the new vnode in the Name Cache only if the top bit isn't set */ + /* And don't enter a new vnode for an invalid one! */ + if (!(vtype & CFS_NOCACHE) && scp == 0) + cfsnc_enter(VTOC(dvp), nm, len, cred, VTOC(*vpp)); + } + } + + exit: + if (scp) vrele(dvp); + /* + * If we are creating, and this was the last name to be looked up, + * and the error was ENOENT, then there really shouldn't be an + * error and we can make the leaf NULL and return success. Since + * this is supposed to work under Mach as well as NetBSD, we're + * leaving this fn wrapped. We also must tell lookup/namei that + * we need to save the last component of the name. (Create will + * have to free the name buffer later...lucky us...) + */ + if (((cnp->cn_nameiop == CREATE) || (cnp->cn_nameiop == RENAME)) + && (cnp->cn_flags & ISLASTCN) + && (error == ENOENT)) + { + error = EJUSTRETURN; + cnp->cn_flags |= SAVENAME; + *ap->a_vpp = NULL; + } + + /* + * If we are removing, and we are at the last element, and we + * found it, then we need to keep the name around so that the + * removal will go ahead as planned. Unfortunately, this will + * probably also lock the to-be-removed vnode, which may or may + * not be a good idea. I'll have to look at the bits of + * cfs_remove to make sure. We'll only save the name if we did in + * fact find the name, otherwise cfs_remove won't have a chance + * to free the pathname. + */ + if ((cnp->cn_nameiop == DELETE) + && (cnp->cn_flags & ISLASTCN) + && !error) + { + cnp->cn_flags |= SAVENAME; + } + + /* + * If the lookup went well, we need to (potentially?) unlock the + * parent, and lock the child. We are only responsible for + * checking to see if the parent is supposed to be unlocked before + * we return. We must always lock the child (provided there is + * one, and (the parent isn't locked or it isn't the same as the + * parent.) Simple, huh? We can never leave the parent locked unless + * we are ISLASTCN + */ + if (!error || (error == EJUSTRETURN)) { + if (!(cnp->cn_flags & LOCKPARENT) || !(cnp->cn_flags & ISLASTCN)) { + if ((error = VOP_X_UNLOCK(dvp, 0))) { + return error; + } + /* + * The parent is unlocked. As long as there is a child, + * lock it without bothering to check anything else. + */ + if (*ap->a_vpp) { + if ((error = VOP_X_LOCK(*ap->a_vpp, LK_EXCLUSIVE))) { + printf("cfs_lookup: "); + panic("unlocked parent but couldn't lock child"); + } + } + } else { + /* The parent is locked, and may be the same as the child */ + if (*ap->a_vpp && (*ap->a_vpp != dvp)) { + /* Different, go ahead and lock it. */ + if ((error = VOP_X_LOCK(*ap->a_vpp, LK_EXCLUSIVE))) { + printf("cfs_lookup: "); + panic("unlocked parent but couldn't lock child"); + } + } + } + } else { + /* If the lookup failed, we need to ensure that the leaf is NULL */ + /* Don't change any locking? */ + *ap->a_vpp = NULL; + } + return(error); +} + +/*ARGSUSED*/ +int +cfs_create(v) + void *v; +{ +/* true args */ + struct vop_create_args *ap = v; + struct vnode *dvp = ap->a_dvp; + struct cnode *dcp = VTOC(dvp); + struct vattr *va = ap->a_vap; + int exclusive = 1; + int mode = ap->a_vap->va_mode; + struct vnode **vpp = ap->a_vpp; + struct componentname *cnp = ap->a_cnp; + struct ucred *cred = cnp->cn_cred; + struct proc *p = cnp->cn_proc; +/* locals */ + int error; + struct cnode *cp; + const char *nm = cnp->cn_nameptr; + int len = cnp->cn_namelen; + ViceFid VFid; + struct vattr attr; + + MARK_ENTRY(CFS_CREATE_STATS); + + /* All creates are exclusive XXX */ + /* I'm assuming the 'mode' argument is the file mode bits XXX */ + + /* Check for create of control object. */ + if (IS_CTL_NAME(dvp, nm, len)) { + *vpp = (struct vnode *)0; + MARK_INT_FAIL(CFS_CREATE_STATS); + return(EACCES); + } + + error = venus_create(vtomi(dvp), &dcp->c_fid, nm, len, exclusive, mode, va, cred, p, &VFid, &attr); + + if (!error) { + + /* If this is an exclusive create, panic if the file already exists. */ + /* Venus should have detected the file and reported EEXIST. */ + + if ((exclusive == 1) && + (cfs_find(&VFid) != NULL)) + panic("cnode existed for newly created file!"); + + cp = makecfsnode(&VFid, dvp->v_mount, attr.va_type); + *vpp = CTOV(cp); + + /* Update va to reflect the new attributes. */ + (*va) = attr; + + /* Update the attribute cache and mark it as valid */ + if (cfs_attr_cache) { + VTOC(*vpp)->c_vattr = attr; + VTOC(*vpp)->c_flags |= C_VATTR; + } + + /* Invalidate the parent's attr cache, the modification time has changed */ + VTOC(dvp)->c_flags &= ~C_VATTR; + + /* enter the new vnode in the Name Cache */ + cfsnc_enter(VTOC(dvp), nm, len, cred, VTOC(*vpp)); + + CFSDEBUG(CFS_CREATE, + myprintf(("create: (%lx.%lx.%lx), result %d\n", + VFid.Volume, VFid.Vnode, VFid.Unique, error)); ) + } else { + *vpp = (struct vnode *)0; + CFSDEBUG(CFS_CREATE, myprintf(("create error %d\n", error));) + } + + /* Locking strategy. */ + /* + * In NetBSD, all creates must explicitly vput their dvp's. We'll + * go ahead and use the LOCKLEAF flag of the cnp argument. + * However, I'm pretty sure that create must return the leaf + * locked; so there is a DIAGNOSTIC check to ensure that this is + * true. + */ +#ifdef __FreeBSD_version + /* + * Well, FreeBSD -current does the vput put in + * kern/vfs_vnops.c.c:vn_open() + */ +#else + vput(dvp); +#endif + if (!error) { + if (cnp->cn_flags & LOCKLEAF) { + if ((error = VOP_X_LOCK(*ap->a_vpp, LK_EXCLUSIVE))) { + printf("cfs_create: "); + panic("unlocked parent but couldn't lock child"); + } + } +#ifdef DIAGNOSTIC + else { + printf("cfs_create: LOCKLEAF not set!\n"); + } +#endif /* DIAGNOSTIC */ + } + /* Have to free the previously saved name */ + /* + * This condition is stolen from ufs_makeinode. I have no idea + * why it's here, but what the hey... + */ + if ((cnp->cn_flags & SAVESTART) == 0) { + NAMEI_FREE(cnp->cn_pnbuf); + } + return(error); +} + +int +cfs_remove(v) + void *v; +{ +/* true args */ + struct vop_remove_args *ap = v; + struct vnode *dvp = ap->a_dvp; + struct cnode *cp = VTOC(dvp); + struct componentname *cnp = ap->a_cnp; + struct ucred *cred = cnp->cn_cred; + struct proc *p = cnp->cn_proc; +/* locals */ + int error; + const char *nm = cnp->cn_nameptr; + int len = cnp->cn_namelen; + struct cnode *tp; + + MARK_ENTRY(CFS_REMOVE_STATS); + + CFSDEBUG(CFS_REMOVE, myprintf(("remove: %s in %lx.%lx.%lx\n", + nm, cp->c_fid.Volume, cp->c_fid.Vnode, + cp->c_fid.Unique));); + + /* Remove the file's entry from the CFS Name Cache */ + /* We're being conservative here, it might be that this person + * doesn't really have sufficient access to delete the file + * but we feel zapping the entry won't really hurt anyone -- dcs + */ + /* I'm gonna go out on a limb here. If a file and a hardlink to it + * exist, and one is removed, the link count on the other will be + * off by 1. We could either invalidate the attrs if cached, or + * fix them. I'll try to fix them. DCS 11/8/94 + */ + tp = cfsnc_lookup(VTOC(dvp), nm, len, cred); + if (tp) { + if (VALID_VATTR(tp)) { /* If attrs are cached */ + if (tp->c_vattr.va_nlink > 1) { /* If it's a hard link */ + tp->c_vattr.va_nlink--; + } + } + + cfsnc_zapfile(VTOC(dvp), nm, len); + /* No need to flush it if it doesn't exist! */ + } + /* Invalidate the parent's attr cache, the modification time has changed */ + VTOC(dvp)->c_flags &= ~C_VATTR; + + /* Check for remove of control object. */ + if (IS_CTL_NAME(dvp, nm, len)) { + MARK_INT_FAIL(CFS_REMOVE_STATS); + return(ENOENT); + } + + error = venus_remove(vtomi(dvp), &cp->c_fid, nm, len, cred, p); + + CFSDEBUG(CFS_REMOVE, myprintf(("in remove result %d\n",error)); ) + +#ifdef __FreeBSD_version + /* + * Well, FreeBSD -current does the vrele/vput put in + * kern/vfs_syscalls.c:unlink() + */ +#else + /* + * Regardless of what happens, we have to unconditionally drop + * locks/refs on parent and child. (I hope). This is based on + * what ufs_remove seems to be doing. + */ + if (dvp == ap->a_vp) { + vrele(ap->a_vp); + } else { + vput(ap->a_vp); + } + vput(dvp); +#endif + + if ((cnp->cn_flags & SAVESTART) == 0) { + NAMEI_FREE(cnp->cn_pnbuf); + } + return(error); +} + +int +cfs_link(v) + void *v; +{ +/* true args */ + struct vop_link_args *ap = v; + struct vnode *vp = ap->a_vp; + struct cnode *cp = VTOC(vp); +#ifdef __NetBSD__ + struct vnode *tdvp = ap->a_dvp; +#elif defined(__FreeBSD__) + struct vnode *tdvp = ap->a_tdvp; +#endif + struct cnode *tdcp = VTOC(tdvp); + struct componentname *cnp = ap->a_cnp; + struct ucred *cred = cnp->cn_cred; + struct proc *p = cnp->cn_proc; +/* locals */ + int error; + const char *nm = cnp->cn_nameptr; + int len = cnp->cn_namelen; + + MARK_ENTRY(CFS_LINK_STATS); + + if (cfsdebug & CFSDBGMSK(CFS_LINK)) { + + myprintf(("nb_link: vp fid: (%lx.%lx.%lx)\n", + cp->c_fid.Volume, cp->c_fid.Vnode, cp->c_fid.Unique)); + myprintf(("nb_link: tdvp fid: (%lx.%lx.%lx)\n", + tdcp->c_fid.Volume, tdcp->c_fid.Vnode, tdcp->c_fid.Unique)); + + } + if (cfsdebug & CFSDBGMSK(CFS_LINK)) { + myprintf(("link: vp fid: (%lx.%lx.%lx)\n", + cp->c_fid.Volume, cp->c_fid.Vnode, cp->c_fid.Unique)); + myprintf(("link: tdvp fid: (%lx.%lx.%lx)\n", + tdcp->c_fid.Volume, tdcp->c_fid.Vnode, tdcp->c_fid.Unique)); + + } + + /* Check for link to/from control object. */ + if (IS_CTL_NAME(tdvp, nm, len) || IS_CTL_VP(vp)) { + MARK_INT_FAIL(CFS_LINK_STATS); + return(EACCES); + } + + /* + * According to the ufs_link operation here's the locking situation: + * We enter with the thing called "dvp" (the directory) locked. + * We must unconditionally drop locks on "dvp" + * + * We enter with the thing called "vp" (the linked-to) unlocked, + * but ref'd (?) + * We seem to need to lock it before calling cfs_link, and + * unconditionally unlock it after. + */ + +#ifdef __FreeBSD_version + /* + * Well, FreeBSD -current does the vrele/vput put in + * kern/vfs_syscalls.c:link() + */ +#else + if ((ap->a_vp != tdvp) && (error = VOP_X_LOCK(ap->a_vp, LK_EXCLUSIVE))) { + goto exit; + } +#endif + + error = venus_link(vtomi(vp), &cp->c_fid, &tdcp->c_fid, nm, len, cred, p); + + /* Invalidate the parent's attr cache, the modification time has changed */ + VTOC(tdvp)->c_flags &= ~C_VATTR; + VTOC(vp)->c_flags &= ~C_VATTR; + + CFSDEBUG(CFS_LINK, myprintf(("in link result %d\n",error)); ) + +exit: + +#ifdef __FreeBSD_version + /* + * Well, FreeBSD -current does the vrele/vput put in + * kern/vfs_syscalls.c:link() + */ +#else + if (ap->a_vp != tdvp) { + VOP_X_UNLOCK(ap->a_vp, 0); + } + vput(tdvp); +#endif + + /* Drop the name buffer if we don't need to SAVESTART */ + if ((cnp->cn_flags & SAVESTART) == 0) { + NAMEI_FREE(cnp->cn_pnbuf); + } + return(error); +} + +int +cfs_rename(v) + void *v; +{ +/* true args */ + struct vop_rename_args *ap = v; + struct vnode *odvp = ap->a_fdvp; + struct cnode *odcp = VTOC(odvp); + struct componentname *fcnp = ap->a_fcnp; + struct vnode *ndvp = ap->a_tdvp; + struct cnode *ndcp = VTOC(ndvp); + struct componentname *tcnp = ap->a_tcnp; + struct ucred *cred = fcnp->cn_cred; + struct proc *p = fcnp->cn_proc; +/* true args */ + int error; + const char *fnm = fcnp->cn_nameptr; + int flen = fcnp->cn_namelen; + const char *tnm = tcnp->cn_nameptr; + int tlen = tcnp->cn_namelen; + + MARK_ENTRY(CFS_RENAME_STATS); + + /* Hmmm. The vnodes are already looked up. Perhaps they are locked? + This could be Bad. XXX */ +#ifdef DIAGNOSTIC + if ((fcnp->cn_cred != tcnp->cn_cred) + || (fcnp->cn_proc != tcnp->cn_proc)) + { + panic("cfs_rename: component names don't agree"); + } +#endif DIAGNOSTIC + + /* Check for rename involving control object. */ + if (IS_CTL_NAME(odvp, fnm, flen) || IS_CTL_NAME(ndvp, tnm, tlen)) { + MARK_INT_FAIL(CFS_RENAME_STATS); + return(EACCES); + } + + /* Problem with moving directories -- need to flush entry for .. */ + if (odvp != ndvp) { + struct cnode *ovcp = cfsnc_lookup(VTOC(odvp), fnm, flen, cred); + if (ovcp) { + struct vnode *ovp = CTOV(ovcp); + if ((ovp) && + (ovp->v_type == VDIR)) /* If it's a directory */ + cfsnc_zapfile(VTOC(ovp),"..", 2); + } + } + + /* Remove the entries for both source and target files */ + cfsnc_zapfile(VTOC(odvp), fnm, flen); + cfsnc_zapfile(VTOC(ndvp), tnm, tlen); + + /* Invalidate the parent's attr cache, the modification time has changed */ + VTOC(odvp)->c_flags &= ~C_VATTR; + VTOC(ndvp)->c_flags &= ~C_VATTR; + + if (flen+1 > CFS_MAXNAMLEN) { + MARK_INT_FAIL(CFS_RENAME_STATS); + error = EINVAL; + goto exit; + } + + if (tlen+1 > CFS_MAXNAMLEN) { + MARK_INT_FAIL(CFS_RENAME_STATS); + error = EINVAL; + goto exit; + } + + error = venus_rename(vtomi(odvp), &odcp->c_fid, &ndcp->c_fid, fnm, flen, tnm, tlen, cred, p); + + exit: + CFSDEBUG(CFS_RENAME, myprintf(("in rename result %d\n",error));) + /* XXX - do we need to call cache pureg on the moved vnode? */ + cache_purge(ap->a_fvp); + + /* It seems to be incumbent on us to drop locks on all four vnodes */ + /* From-vnodes are not locked, only ref'd. To-vnodes are locked. */ + + vrele(ap->a_fvp); + vrele(odvp); + + if (ap->a_tvp) { + if (ap->a_tvp == ndvp) { + vrele(ap->a_tvp); + } else { + vput(ap->a_tvp); + } + } + + vput(ndvp); + return(error); +} + +int +cfs_mkdir(v) + void *v; +{ +/* true args */ + struct vop_mkdir_args *ap = v; + struct vnode *dvp = ap->a_dvp; + struct cnode *dcp = VTOC(dvp); + struct componentname *cnp = ap->a_cnp; + register struct vattr *va = ap->a_vap; + struct vnode **vpp = ap->a_vpp; + struct ucred *cred = cnp->cn_cred; + struct proc *p = cnp->cn_proc; +/* locals */ + int error; + const char *nm = cnp->cn_nameptr; + int len = cnp->cn_namelen; + struct cnode *cp; + ViceFid VFid; + struct vattr ova; + + MARK_ENTRY(CFS_MKDIR_STATS); + + /* Check for mkdir of target object. */ + if (IS_CTL_NAME(dvp, nm, len)) { + *vpp = (struct vnode *)0; + MARK_INT_FAIL(CFS_MKDIR_STATS); + return(EACCES); + } + + if (len+1 > CFS_MAXNAMLEN) { + *vpp = (struct vnode *)0; + MARK_INT_FAIL(CFS_MKDIR_STATS); + return(EACCES); + } + + error = venus_mkdir(vtomi(dvp), &dcp->c_fid, nm, len, va, cred, p, &VFid, &ova); + + if (!error) { + if (cfs_find(&VFid) != NULL) + panic("cnode existed for newly created directory!"); + + + cp = makecfsnode(&VFid, dvp->v_mount, va->va_type); + *vpp = CTOV(cp); + + /* enter the new vnode in the Name Cache */ + cfsnc_enter(VTOC(dvp), nm, len, cred, VTOC(*vpp)); + + /* as a side effect, enter "." and ".." for the directory */ + cfsnc_enter(VTOC(*vpp), ".", 1, cred, VTOC(*vpp)); + cfsnc_enter(VTOC(*vpp), "..", 2, cred, VTOC(dvp)); + + if (cfs_attr_cache) { + VTOC(*vpp)->c_vattr = ova; /* update the attr cache */ + VTOC(*vpp)->c_flags |= C_VATTR; /* Valid attributes in cnode */ + } + + /* Invalidate the parent's attr cache, the modification time has changed */ + VTOC(dvp)->c_flags &= ~C_VATTR; + + CFSDEBUG( CFS_MKDIR, myprintf(("mkdir: (%lx.%lx.%lx) result %d\n", + VFid.Volume, VFid.Vnode, VFid.Unique, error)); ) + } else { + *vpp = (struct vnode *)0; + CFSDEBUG(CFS_MKDIR, myprintf(("mkdir error %d\n",error));) + } + + /* + * Currently, all mkdirs explicitly vput their dvp's. + * It also appears that we *must* lock the vpp, since + * lockleaf isn't set, but someone down the road is going + * to try to unlock the new directory. + */ +#ifdef __FreeBSD_version + /* + * Well, FreeBSD -current does the vrele/vput put in + * kern/vfs_syscalls.c:mkdir() + */ +#else + vput(dvp); + if (!error) { + if ((error = VOP_X_LOCK(*ap->a_vpp, LK_EXCLUSIVE))) { + panic("cfs_mkdir: couldn't lock child"); + } + } +#endif + + /* Have to free the previously saved name */ + /* + * ufs_mkdir doesn't check for SAVESTART before freeing the + * pathname buffer, but ufs_create does. For the moment, I'll + * follow their lead, but this seems like it is probably + * incorrect. + */ + NAMEI_FREE(cnp->cn_pnbuf); + return(error); +} + +int +cfs_rmdir(v) + void *v; +{ +/* true args */ + struct vop_rmdir_args *ap = v; + struct vnode *dvp = ap->a_dvp; + struct cnode *dcp = VTOC(dvp); + struct componentname *cnp = ap->a_cnp; + struct ucred *cred = cnp->cn_cred; + struct proc *p = cnp->cn_proc; +/* true args */ + int error; + const char *nm = cnp->cn_nameptr; + int len = cnp->cn_namelen; + struct cnode *cp; + + MARK_ENTRY(CFS_RMDIR_STATS); + + /* Check for rmdir of control object. */ + if (IS_CTL_NAME(dvp, nm, len)) { + MARK_INT_FAIL(CFS_RMDIR_STATS); + return(ENOENT); + } + + /* We're being conservative here, it might be that this person + * doesn't really have sufficient access to delete the file + * but we feel zapping the entry won't really hurt anyone -- dcs + */ + /* + * As a side effect of the rmdir, remove any entries for children of + * the directory, especially "." and "..". + */ + cp = cfsnc_lookup(dcp, nm, len, cred); + if (cp) cfsnc_zapParentfid(&(cp->c_fid), NOT_DOWNCALL); + + /* Remove the file's entry from the CFS Name Cache */ + cfsnc_zapfile(dcp, nm, len); + + /* Invalidate the parent's attr cache, the modification time has changed */ + dcp->c_flags &= ~C_VATTR; + + error = venus_rmdir(vtomi(dvp), &dcp->c_fid, nm, len, cred, p); + + CFSDEBUG(CFS_RMDIR, myprintf(("in rmdir result %d\n", error)); ) + +#ifdef __FreeBSD_version + /* + * Well, FreeBSD -current does the vrele/vput put in + * kern/vfs_syscalls.c:rmdir() + */ +#else + /* + * regardless of what happens, we need to drop locks/refs on the + * parent and child. I think. + */ + if (dvp == ap->a_vp) { + vrele(ap->a_vp); + } else { + vput(ap->a_vp); + } + vput(dvp); +#endif + + if ((cnp->cn_flags & SAVESTART) == 0) { + NAMEI_FREE(cnp->cn_pnbuf); + } + return(error); +} + +int +cfs_symlink(v) + void *v; +{ +/* true args */ + struct vop_symlink_args *ap = v; + struct vnode *tdvp = ap->a_dvp; + struct cnode *tdcp = VTOC(tdvp); + struct componentname *cnp = ap->a_cnp; + struct vattr *tva = ap->a_vap; + char *path = ap->a_target; + struct ucred *cred = cnp->cn_cred; + struct proc *p = cnp->cn_proc; +/* locals */ + int error; + /* + * XXX I'm assuming the following things about cfs_symlink's + * arguments: + * t(foo) is the new name/parent/etc being created. + * lname is the contents of the new symlink. + */ +#ifdef NetBSD1_3 + const +#endif + char *nm = cnp->cn_nameptr; + int len = cnp->cn_namelen; + int plen = strlen(path); + + /* XXX What about the vpp argument? Do we need it? */ + /* + * Here's the strategy for the moment: perform the symlink, then + * do a lookup to grab the resulting vnode. I know this requires + * two communications with Venus for a new sybolic link, but + * that's the way the ball bounces. I don't yet want to change + * the way the Mach symlink works. When Mach support is + * deprecated, we should change symlink so that the common case + * returns the resultant vnode in a vpp argument. + */ + + MARK_ENTRY(CFS_SYMLINK_STATS); + + /* Check for symlink of control object. */ + if (IS_CTL_NAME(tdvp, nm, len)) { + MARK_INT_FAIL(CFS_SYMLINK_STATS); + return(EACCES); + } + + if (plen+1 > CFS_MAXPATHLEN) { + MARK_INT_FAIL(CFS_SYMLINK_STATS); + return(EINVAL); + } + + if (len+1 > CFS_MAXNAMLEN) { + MARK_INT_FAIL(CFS_SYMLINK_STATS); + error = EINVAL; + goto exit; + } + + error = venus_symlink(vtomi(tdvp), &tdcp->c_fid, path, plen, nm, len, tva, cred, p); + + /* Invalidate the parent's attr cache, the modification time has changed */ + tdcp->c_flags &= ~C_VATTR; + +#ifdef __FreeBSD_version + +#else + if (!error) + { + struct nameidata nd; + NDINIT(&nd, LOOKUP, FOLLOW|LOCKLEAF, UIO_SYSSPACE, nm, p); + nd.ni_cnd.cn_cred = cred; + nd.ni_loopcnt = 0; + nd.ni_startdir = tdvp; + nd.ni_cnd.cn_pnbuf = (char *)nm; + nd.ni_cnd.cn_nameptr = nd.ni_cnd.cn_pnbuf; + nd.ni_pathlen = len; + vput(tdvp); + error = lookup(&nd); + *ap->a_vpp = nd.ni_vp; + } + + /* + * Okay, now we have to drop locks on dvp. vpp is unlocked, but + * ref'd. It doesn't matter what happens in either symlink or + * lookup. Furthermore, there isn't any way for (dvp == *vpp), so + * we don't bother checking. + */ +/* vput(ap->a_dvp); released earlier */ + if (*ap->a_vpp) { + VOP_X_UNLOCK(*ap->a_vpp, 0); /* this line is new!! It is necessary because lookup() calls + VOP_LOOKUP (cfs_lookup) which returns vpp locked. cfs_nb_lookup + merged with cfs_lookup() to become cfs_lookup so UNLOCK is + necessary */ + vrele(*ap->a_vpp); + } +#endif + + /* + * Free the name buffer + */ + if ((cnp->cn_flags & SAVESTART) == 0) { + NAMEI_FREE(cnp->cn_pnbuf); + } + + exit: + CFSDEBUG(CFS_SYMLINK, myprintf(("in symlink result %d\n",error)); ) + return(error); +} + +/* + * Read directory entries. + */ +int +cfs_readdir(v) + void *v; +{ +/* true args */ + struct vop_readdir_args *ap = v; + struct vnode *vp = ap->a_vp; + struct cnode *cp = VTOC(vp); + register struct uio *uiop = ap->a_uio; + struct ucred *cred = ap->a_cred; + int *eofflag = ap->a_eofflag; +#if defined(__NetBSD__) && defined(NetBSD1_3) && (NetBSD1_3 >= 7) + off_t **cookies = ap->a_cookies; + int *ncookies = ap->a_ncookies; +#elif defined(NetBSD1_3) + off_t *cookies = ap->a_cookies; + int ncookies = ap->a_ncookies; +#elif NetBSD1_2 + u_long *cookies = ap->a_cookies; + int ncookies = ap->a_ncookies; +#elif defined(__FreeBSD__) && defined(__FreeBSD_version) + u_long **cookies = ap->a_cookies; + int *ncookies = ap->a_ncookies; +#elif defined(__FreeBSD__) + u_int **cookies = ap->a_cookies; + int *ncookies = ap->a_ncookies; +#endif + struct proc *p = ap->a_uio->uio_procp; +/* upcall decl */ +/* locals */ + int error = 0; + + MARK_ENTRY(CFS_READDIR_STATS); + + CFSDEBUG(CFS_READDIR, myprintf(("cfs_readdir(%p, %d, %qd, %d)\n", uiop->uio_iov->iov_base, uiop->uio_resid, uiop->uio_offset, uiop->uio_segflg)); ) + + /* Check for readdir of control object. */ + if (IS_CTL_VP(vp)) { + MARK_INT_FAIL(CFS_READDIR_STATS); + return(ENOENT); + } + + if (cfs_intercept_rdwr) { + /* Redirect the request to UFS. */ + + /* If directory is not already open do an "internal open" on it. */ + int opened_internally = 0; + if (cp->c_ovp == NULL) { + opened_internally = 1; + MARK_INT_GEN(CFS_OPEN_STATS); + error = VOP_OPEN(vp, FREAD, cred, p); +printf("cfs_readdir: Internally Opening %p\n", vp); +#ifdef __FreeBSD__ + if (error) { + printf("cfs_readdir: VOP_OPEN on container failed %d\n", error); + return (error); + } + if (vp->v_type == VREG) { + error = vfs_object_create(vp, p, cred, 1); + if (error != 0) { + printf("cfs_readdir: vfs_object_create() returns %d\n", error); + vput(vp); + } + } +#endif + if (error) return(error); + } + + /* Have UFS handle the call. */ + CFSDEBUG(CFS_READDIR, myprintf(("indirect readdir: fid = (%lx.%lx.%lx), refcnt = %d\n",cp->c_fid.Volume, cp->c_fid.Vnode, cp->c_fid.Unique, vp->v_usecount)); ) +#ifdef __NetBSD__ + error = VOP_READDIR(cp->c_ovp, uiop, cred, eofflag, cookies, + ncookies); +#elif defined(__FreeBSD__) + error = VOP_READDIR(cp->c_ovp, uiop, cred, eofflag, ncookies, + cookies); +#endif + + if (error) + MARK_INT_FAIL(CFS_READDIR_STATS); + else + MARK_INT_SAT(CFS_READDIR_STATS); + + /* Do an "internal close" if necessary. */ + if (opened_internally) { + MARK_INT_GEN(CFS_CLOSE_STATS); + (void)VOP_CLOSE(vp, FREAD, cred, p); + } + } + else { + /* Read the block from Venus. */ + struct iovec *iovp = uiop->uio_iov; + unsigned count = iovp->iov_len; + int size; + + + /* Make the count a multiple of DIRBLKSIZ (borrowed from ufs_readdir). */ +#define DIRBLKSIZ DEV_BSIZE + if ((uiop->uio_iovcnt != 1) || (count < DIRBLKSIZ) || + (uiop->uio_offset & (DIRBLKSIZ - 1))) + return (EINVAL); + count &= ~(DIRBLKSIZ - 1); + uiop->uio_resid -= iovp->iov_len - count; + iovp->iov_len = count; + if (count > VC_MAXDATASIZE) + return(EINVAL); + + + error = venus_readdir(vtomi(CTOV(cp)), &cp->c_fid, count, uiop->uio_offset, cred, p, iovp->iov_base, &size); + + CFSDEBUG(CFS_READDIR, + myprintf(("cfs_readdir(%p, %d, %qd, %d) returns (%d, %d)\n", + iovp->iov_base, count, + uiop->uio_offset, uiop->uio_segflg, error, + size)); ) + if (!error) { + iovp->iov_base += size; + iovp->iov_len -= size; + uiop->uio_resid -= size; + uiop->uio_offset += size; + } + } + + return(error); +} + +/* + * Convert from file system blocks to device blocks + */ +int +cfs_bmap(v) + void *v; +{ + /* XXX on the global proc */ +/* true args */ + struct vop_bmap_args *ap = v; + struct vnode *vp __attribute__((unused)) = ap->a_vp; /* file's vnode */ + daddr_t bn __attribute__((unused)) = ap->a_bn; /* fs block number */ + struct vnode **vpp = ap->a_vpp; /* RETURN vp of device */ + daddr_t *bnp __attribute__((unused)) = ap->a_bnp; /* RETURN device block number */ + struct proc *p __attribute__((unused)) = curproc; +/* upcall decl */ +/* locals */ + +#ifdef __FreeBSD__ +#ifdef __FreeBSD_version + int ret = 0; + struct cnode *cp; + + cp = VTOC(vp); + if (cp->c_ovp) { + printf("cfs_bmap: container .. "); + ret = VOP_BMAP(cp->c_ovp, bn, vpp, bnp, ap->a_runp, ap->a_runb); + printf("VOP_BMAP(cp->c_ovp %p, bn %p, vpp %p, bnp %p, ap->a_runp %p, ap->a_runb %p) = %d\n", + cp->c_ovp, bn, vpp, bnp, ap->a_runp, ap->a_runb, ret); + return ret; + } else { + printf("cfs_bmap: no container\n"); + return(EOPNOTSUPP); + } +#else + /* Just like nfs_bmap(). Do not touch *vpp, this cause pfault. */ + return(EOPNOTSUPP); +#endif +#else /* !FreeBSD */ + *vpp = (struct vnode *)0; + myprintf(("cfs_bmap called!\n")); + return(EINVAL); +#endif +} + +/* + * I don't think the following two things are used anywhere, so I've + * commented them out + * + * struct buf *async_bufhead; + * int async_daemon_count; + */ +int +cfs_strategy(v) + void *v; +{ +/* true args */ + struct vop_strategy_args *ap = v; + register struct buf *bp __attribute__((unused)) = ap->a_bp; + struct proc *p __attribute__((unused)) = curproc; +/* upcall decl */ +/* locals */ + +#ifdef __FreeBSD__ +#ifdef __FreeBSD_version + printf("cfs_strategy: called ???\n"); + return(EOPNOTSUPP); +#else /* ! __MAYBE_FreeBSD__ */ + myprintf(("cfs_strategy called! ")); + return(EOPNOTSUPP); +#endif /* __MAYBE_FreeBSD__ */ +#else /* ! __FreeBSD__ */ + myprintf(("cfs_strategy called! ")); + return(EINVAL); +#endif /* __FreeBSD__ */ +} + +int +cfs_reclaim(v) + void *v; +{ +/* true args */ + struct vop_reclaim_args *ap = v; + struct vnode *vp = ap->a_vp; + struct cnode *cp = VTOC(vp); +/* upcall decl */ +/* locals */ + +/* + * Forced unmount/flush will let vnodes with non zero use be destroyed! + */ + ENTRY; + + if (IS_UNMOUNTING(cp)) { +#ifdef DEBUG + if (VTOC(vp)->c_ovp) { + if (IS_UNMOUNTING(cp)) + printf("cfs_reclaim: c_ovp not void: vp %p, cp %p\n", vp, cp); + } +#endif + } else { +#ifdef DIAGNOSTIC + if (vp->v_usecount != 0) + vprint("cfs_reclaim: pushing active", vp); + if (VTOC(vp)->c_ovp) { + panic("cfs_reclaim: c_ovp not void"); + } +#endif DIAGNOSTIC + } + cache_purge(vp); + cfs_free(VTOC(vp)); + VTOC(vp) = NULL; + return (0); +} + +#ifdef NEW_LOCKMGR +int +cfs_lock(v) + void *v; +{ +/* true args */ + struct vop_lock_args *ap = v; + struct vnode *vp = ap->a_vp; + struct cnode *cp = VTOC(vp); +#ifdef __FreeBSD_version + struct proc *p = ap->a_p; +#endif +/* upcall decl */ +/* locals */ + + ENTRY; + + if (cfs_lockdebug) { + myprintf(("Attempting lock on %lx.%lx.%lx\n", + cp->c_fid.Volume, cp->c_fid.Vnode, cp->c_fid.Unique)); + } + + return (NEW_LOCKMGR(&cp->c_lock, ap->a_flags, &vp->v_interlock)); +} + +int +cfs_unlock(v) + void *v; +{ +/* true args */ + struct vop_unlock_args *ap = v; + struct vnode *vp = ap->a_vp; + struct cnode *cp = VTOC(vp); +#ifdef __FreeBSD_version + struct proc *p = ap->a_p; +#endif +/* upcall decl */ +/* locals */ + + ENTRY; + if (cfs_lockdebug) { + myprintf(("Attempting unlock on %lx.%lx.%lx\n", + cp->c_fid.Volume, cp->c_fid.Vnode, cp->c_fid.Unique)); + } + + return (NEW_LOCKMGR(&cp->c_lock, ap->a_flags | LK_RELEASE, &vp->v_interlock)); +} + +int +cfs_islocked(v) + void *v; +{ +/* true args */ + struct vop_islocked_args *ap = v; + struct cnode *cp = VTOC(ap->a_vp); + ENTRY; + + return (lockstatus(&cp->c_lock)); +} +#else +int +cfs_lock(v) + void *v; +{ +/* true args */ + struct vop_lock_args *ap = v; + struct vnode *vp = ap->a_vp; + struct cnode *cp; + struct proc *p __attribute__((unused)) = curproc; /* XXX */ +/* upcall decl */ +/* locals */ + + ENTRY; + cp = VTOC(vp); + + if (cfs_lockdebug) { + myprintf(("Attempting lock on %lx.%lx.%lx\n", + cp->c_fid.Volume, cp->c_fid.Vnode, cp->c_fid.Unique)); + } +start: + while (vp->v_flag & VXLOCK) { + vp->v_flag |= VXWANT; +#ifdef __NetBSD__ + (void) sleep((caddr_t)vp, PINOD); +#elif defined(__FreeBSD__) + (void) tsleep((caddr_t)vp, PINOD, "cfs_lock1", 0); +#endif + } + if (vp->v_tag == VT_NON) + return (ENOENT); + + if (cp->c_flags & C_LOCKED) { + cp->c_flags |= C_WANTED; +#ifdef DIAGNOSTIC + myprintf(("cfs_lock: lock contention")); + cfsnc_name(cp); + myprintf(("\n")); +#endif +#ifdef __NetBSD__ + (void) sleep((caddr_t)cp, PINOD); +#elif defined(__FreeBSD__) + (void) tsleep((caddr_t)cp, PINOD, "cfs_lock2", 0); +#endif +#ifdef DIAGNOSTIC + myprintf(("cfs_lock: contention resolved\n")); +#endif + goto start; + } + cp->c_flags |= C_LOCKED; + return (0); +} + +int +cfs_unlock(v) + void *v; +{ +/* true args */ + struct vop_unlock_args *ap = v; + struct cnode *cp = VTOC(ap->a_vp); +/* upcall decl */ +/* locals */ + + ENTRY; + if (cfs_lockdebug) { + myprintf(("Attempting unlock on %lx.%lx.%lx\n", + cp->c_fid.Volume, cp->c_fid.Vnode, cp->c_fid.Unique)); + } +#ifdef DIAGNOSTIC + if ((cp->c_flags & C_LOCKED) == 0) + panic("cfs_unlock: not locked"); +#endif + cp->c_flags &= ~C_LOCKED; + if (cp->c_flags & C_WANTED) { + cp->c_flags &= ~C_WANTED; + wakeup((caddr_t)cp); + } + return (0); +} + +int +cfs_islocked(v) + void *v; +{ +/* true args */ + struct vop_islocked_args *ap = v; + + ENTRY; + if (VTOC(ap->a_vp)->c_flags & C_LOCKED) + return (1); + return (0); +} +#endif + +/* How one looks up a vnode given a device/inode pair: */ +int +cfs_grab_vnode(dev_t dev, ino_t ino, struct vnode **vpp) +{ + /* This is like VFS_VGET() or igetinode()! */ + int error; + struct mount *mp; + + if (!(mp = devtomp(dev))) { + myprintf(("cfs_grab_vnode: devtomp(%d) returns NULL\n", dev)); + return(ENXIO); + } + + /* XXX - ensure that nonzero-return means failure */ + error = VFS_VGET(mp,ino,vpp); + if (error) { + myprintf(("cfs_grab_vnode: iget/vget(%d, %d) returns %p, err %d\n", + dev, ino, *vpp, error)); + return(ENOENT); + } + return(0); +} + +void +print_vattr( attr ) + struct vattr *attr; +{ + char *typestr; + + switch (attr->va_type) { + case VNON: + typestr = "VNON"; + break; + case VREG: + typestr = "VREG"; + break; + case VDIR: + typestr = "VDIR"; + break; + case VBLK: + typestr = "VBLK"; + break; + case VCHR: + typestr = "VCHR"; + break; + case VLNK: + typestr = "VLNK"; + break; + case VSOCK: + typestr = "VSCK"; + break; + case VFIFO: + typestr = "VFFO"; + break; + case VBAD: + typestr = "VBAD"; + break; + default: + typestr = "????"; + break; + } + + + myprintf(("attr: type %s mode %d uid %d gid %d fsid %d rdev %d\n", + typestr, (int)attr->va_mode, (int)attr->va_uid, + (int)attr->va_gid, (int)attr->va_fsid, (int)attr->va_rdev)); + + myprintf((" fileid %d nlink %d size %d blocksize %d bytes %d\n", + (int)attr->va_fileid, (int)attr->va_nlink, + (int)attr->va_size, + (int)attr->va_blocksize,(int)attr->va_bytes)); + myprintf((" gen %ld flags %ld vaflags %d\n", + attr->va_gen, attr->va_flags, attr->va_vaflags)); + myprintf((" atime sec %d nsec %d\n", + (int)attr->va_atime.tv_sec, (int)attr->va_atime.tv_nsec)); + myprintf((" mtime sec %d nsec %d\n", + (int)attr->va_mtime.tv_sec, (int)attr->va_mtime.tv_nsec)); + myprintf((" ctime sec %d nsec %d\n", + (int)attr->va_ctime.tv_sec, (int)attr->va_ctime.tv_nsec)); +} + +/* How to print a ucred */ +void +print_cred(cred) + struct ucred *cred; +{ + + int i; + + myprintf(("ref %d\tuid %d\n",cred->cr_ref,cred->cr_uid)); + + for (i=0; i < cred->cr_ngroups; i++) + myprintf(("\tgroup %d: (%d)\n",i,cred->cr_groups[i])); + myprintf(("\n")); + +} + +/* + ----------------------------------------------------------------------------------- + */ + +/* + * Return a vnode for the given fid. + * If no cnode exists for this fid create one and put it + * in a table hashed by fid.Volume and fid.Vnode. If the cnode for + * this fid is already in the table return it (ref count is + * incremented by cfs_find. The cnode will be flushed from the + * table when cfs_inactive calls cfs_unsave. + */ +struct cnode * +makecfsnode(fid, vfsp, type) + ViceFid *fid; struct mount *vfsp; short type; +{ + struct cnode *cp; + int err; + + if ((cp = cfs_find(fid)) == NULL) { + struct vnode *vp; + + cp = cfs_alloc(); +#ifdef NEW_LOCKMGR + lockinit(&cp->c_lock, PINOD, "cnode", 0, 0); +#endif + cp->c_fid = *fid; + + err = getnewvnode(VT_CFS, vfsp, cfs_vnodeop_p, &vp); + if (err) { + panic("cfs: getnewvnode returned error %d\n", err); + } + vp->v_data = cp; + vp->v_type = type; + cp->c_vnode = vp; + cfs_save(cp); + + } else { + vref(CTOV(cp)); + } + + return cp; +} + + + +#ifdef MACH +/* + * read a logical block and return it in a buffer */ +int +cfs_bread(vp, lbn, bpp) + struct vnode *vp; + daddr_t lbn; + struct buf **bpp; +{ + myprintf(("cfs_bread called!\n")); + return(EINVAL); +} + +/* + * release a block returned by cfs_bread + */ +int +cfs_brelse(vp, bp) + struct vnode *vp; + struct buf *bp; +{ + + myprintf(("cfs_brelse called!\n")); + return(EINVAL); +} + +int +cfs_badop() +{ + panic("cfs_badop"); +} + +int +cfs_noop() +{ + return (EINVAL); +} + +int +cfs_fid(vp, fidpp) + struct vnode *vp; + struct fid **fidpp; +{ + struct cfid *cfid; + + cfid = (struct cfid *)kalloc(sizeof(struct cfid)); + bzero((caddr_t)cfid, sizeof(struct cfid)); + cfid->cfid_len = sizeof(struct cfid) - (sizeof(struct fid) - MAXFIDSZ); + cfid->cfid_fid = VTOC(vp)->c_fid; + *fidpp = (struct fid *)cfid; + return (0); +} + +int +cfs_freefid(vp, fidp) + struct vnode *vp; + struct fid *fidp; +{ + kfree((struct cfid *)fidp, sizeof(struct cfid)); + return (0); +} + +/* + * Record-locking requests are passed to the local Lock-Manager daemon. + */ +int +cfs_lockctl(vp, ld, cmd, cred) + struct vnode *vp; + struct flock *ld; + int cmd; + struct ucred *cred; +{ + myprintf(("cfs_lockctl called!\n")); + return(EINVAL); +} + +cfs_page_read(vp, buffer, size, offset, cred) + struct vnode *vp; + caddr_t buffer; + int size; + vm_offset_t offset; + struct ucred *cred; +{ + struct cnode *cp = VTOC(vp); + struct uio uio; + struct iovec iov; + int error = 0; + + CFSDEBUG(CFS_RDWR, myprintf(("cfs_page_read(%p, %d, %d), fid = (%lx.%lx.%lx), refcnt = %d\n", buffer, size, offset, VTOC(vp)->c_fid.Volume, VTOC(vp)->c_fid.Vnode, VTOC(vp)->c_fid.Unique, vp->v_count)); ) + + iov.iov_base = buffer; + iov.iov_len = size; + uio.uio_iov = &iov; + uio.uio_iovcnt = 1; + uio.uio_offset = offset; + uio.uio_segflg = UIO_SYSSPACE; + uio.uio_resid = size; + error = cfs_rdwr(vp, &uio, UIO_READ, 0, cred); + if (error) { + myprintf(("error %d on pagein (cfs_rdwr)\n", error)); + error = EIO; + } + +/* + if (!error && (cp->states & CWired) == 0) + cfs_Wire(cp); +*/ + + return(error); +} + +cfs_page_write(vp, buffer, size, offset, cred, init) + struct vnode *vp; + caddr_t buffer; + int size; + vm_offset_t offset; + struct ucred *cred; + boolean_t init; +{ + struct cnode *cp = VTOC(vp); + struct uio uio; + struct iovec iov; + int error = 0; + + CFSDEBUG(CFS_RDWR, myprintf(("cfs_page_write(%p, %d, %d), fid = (%lx.%lx.%lx), refcnt = %d\n", buffer, size, offset, VTOC(vp)->c_fid.Volume, VTOC(vp)->c_fid.Vnode, VTOC(vp)->c_fid.Unique, vp->v_count)); ) + + if (init) { + panic("cfs_page_write: called from data_initialize"); + } + + iov.iov_base = buffer; + iov.iov_len = size; + uio.uio_iov = &iov; + uio.uio_iovcnt = 1; + uio.uio_offset = offset; + uio.uio_segflg = UIO_SYSSPACE; + uio.uio_resid = size; + error = cfs_rdwr(vp, &uio, UIO_WRITE, 0, cred); + if (error) { + myprintf(("error %d on pageout (cfs_rdwr)\n", error)); + error = EIO; + } + + return(error); +} + +#endif diff --git a/sys/fs/coda/coda_vnops.h b/sys/fs/coda/coda_vnops.h new file mode 100644 index 0000000..697cb91 --- /dev/null +++ b/sys/fs/coda/coda_vnops.h @@ -0,0 +1,138 @@ +/* + + 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. +*/ + +/* $Header: /afs/cs/project/coda-src/cvs/coda/kernel-src/vfs/freebsd/cfs/cfs_vnodeops.h,v 1.7 1998/08/28 18:12:24 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: cfs_vnodeops.h,v $ + * Revision 1.7 1998/08/28 18:12:24 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.6 1998/08/18 17:05:22 rvb + * Don't use __RCSID now + * + * Revision 1.5 1998/08/18 16:31:47 rvb + * Sync the code for NetBSD -current; test on 1.3 later + * + * Revision 1.4 98/01/23 11:53:49 rvb + * Bring RVB_CFS1_1 to HEAD + * + * Revision 1.3.2.3 98/01/23 11:21:13 rvb + * Sync with 2.2.5 + * + * Revision 1.3.2.2 97/12/16 12:40:20 rvb + * Sync with 1.3 + * + * Revision 1.3.2.1 97/12/10 14:08:34 rvb + * Fix O_ flags; check result in cfscall + * + * Revision 1.3 97/12/05 10:39:25 rvb + * Read CHANGES + * + * Revision 1.2.34.2 97/11/20 11:46:54 rvb + * Capture current cfs_venus + * + * Revision 1.2.34.1 97/11/13 22:03:04 rvb + * pass2 cfs_NetBSD.h mt + * + * Revision 1.2 96/01/02 16:57:14 bnoble + * Added support for Coda MiniCache and raw inode calls (final commit) + * + * Revision 1.1.2.1 1995/12/20 01:57:40 bnoble + * Added CFS-specific files + * + */ + + +/* NetBSD interfaces to the vnodeops */ +int cfs_open __P((void *)); +int cfs_close __P((void *)); +int cfs_read __P((void *)); +int cfs_write __P((void *)); +int cfs_ioctl __P((void *)); +/* 1.3 int cfs_select __P((void *));*/ +int cfs_getattr __P((void *)); +int cfs_setattr __P((void *)); +int cfs_access __P((void *)); +int cfs_abortop __P((void *)); +int cfs_readlink __P((void *)); +int cfs_fsync __P((void *)); +int cfs_inactive __P((void *)); +int cfs_lookup __P((void *)); +int cfs_create __P((void *)); +int cfs_remove __P((void *)); +int cfs_link __P((void *)); +int cfs_rename __P((void *)); +int cfs_mkdir __P((void *)); +int cfs_rmdir __P((void *)); +int cfs_symlink __P((void *)); +int cfs_readdir __P((void *)); +int cfs_bmap __P((void *)); +int cfs_strategy __P((void *)); +int cfs_reclaim __P((void *)); +int cfs_lock __P((void *)); +int cfs_unlock __P((void *)); +int cfs_islocked __P((void *)); +int nbsd_vop_error __P((void *)); +int nbsd_vop_nop __P((void *)); +#ifdef __FreeBSD__ +int fbsd_vnotsup __P((void *ap)); +#ifdef __FreeBSD_version +int cfs_fbsd_getpages __P((void *)); +int cfs_fbsd_putpages __P((void *)); +#endif +#endif + +int (**cfs_vnodeop_p)(void *); +int cfs_rdwr(struct vnode *vp, struct uio *uiop, enum uio_rw rw, + int ioflag, struct ucred *cred, struct proc *p); + + + +int cfs_grab_vnode(dev_t dev, ino_t ino, struct vnode **vpp); +void print_vattr(struct vattr *attr); +void print_cred(struct ucred *cred); -- cgit v1.1