summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorArtur Grabowski <art@cvs.openbsd.org>1999-04-30 01:59:18 +0000
committerArtur Grabowski <art@cvs.openbsd.org>1999-04-30 01:59:18 +0000
commit07b4a33ad356d7a2d300f6ca586637879e4ad5fd (patch)
tree9ea7e04a0d6f54ee8c45d6d897eb401f906e5032 /usr.sbin
parentb0d7a6a83d7eaa1e9a526c576527d81957b28268 (diff)
Import of arla-0.35.7
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/afs/src/arlad/darla.c104
-rw-r--r--usr.sbin/afs/src/arlad/darla.h51
-rw-r--r--usr.sbin/afs/src/arlad/discon.h339
-rw-r--r--usr.sbin/afs/src/arlad/discon_log.c480
-rw-r--r--usr.sbin/afs/src/arlad/discon_log.h268
-rw-r--r--usr.sbin/afs/src/arlad/fs_errors.h92
-rw-r--r--usr.sbin/afs/src/arlad/reconnect.c2172
-rw-r--r--usr.sbin/afs/src/arlad/reconnect.h39
-rw-r--r--usr.sbin/afs/src/lib/ko/vlmisc.c92
-rw-r--r--usr.sbin/afs/src/lwp/plwp.c939
-rw-r--r--usr.sbin/afs/src/lwp/plwp.h191
-rw-r--r--usr.sbin/afs/src/lwp/process-vpp.s171
-rw-r--r--usr.sbin/afs/src/lwp/rw.c255
-rw-r--r--usr.sbin/afs/src/rx/rx-new.h239
-rw-r--r--usr.sbin/afs/src/rx/rxgencon.h39
-rw-r--r--usr.sbin/afs/src/rxdef/rx_pkt.xg77
-rw-r--r--usr.sbin/afs/src/util/heap.c295
-rw-r--r--usr.sbin/afs/src/util/heap.h91
-rw-r--r--usr.sbin/afs/src/util/heaptest.c120
19 files changed, 6054 insertions, 0 deletions
diff --git a/usr.sbin/afs/src/arlad/darla.c b/usr.sbin/afs/src/arlad/darla.c
new file mode 100644
index 00000000000..886d2e5eba0
--- /dev/null
+++ b/usr.sbin/afs/src/arlad/darla.c
@@ -0,0 +1,104 @@
+/* $OpenBSD: darla.c,v 1.1 1999/04/30 01:59:07 art Exp $ */
+/* COPYRIGHT (C) 1998
+ * THE REGENTS OF THE UNIVERSITY OF MICHIGAN
+ * ALL RIGHTS RESERVED
+ *
+ * PERMISSION IS GRANTED TO USE, COPY, CREATE DERIVATIVE WORKS
+ * AND REDISTRIBUTE THIS SOFTWARE AND SUCH DERIVATIVE WORKS
+ * FOR ANY PURPOSE, SO LONG AS THE NAME OF THE UNIVERSITY OF
+ * MICHIGAN IS NOT USED IN ANY ADVERTISING OR PUBLICITY
+ * PERTAINING TO THE USE OR DISTRIBUTION OF THIS SOFTWARE
+ * WITHOUT SPECIFIC, WRITTEN PRIOR AUTHORIZATION. IF THE
+ * ABOVE COPYRIGHT NOTICE OR ANY OTHER IDENTIFICATION OF THE
+ * UNIVERSITY OF MICHIGAN IS INCLUDED IN ANY COPY OF ANY
+ * PORTION OF THIS SOFTWARE, THEN THE DISCLAIMER BELOW MUST
+ * ALSO BE INCLUDED.
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
+ * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
+ * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
+ * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
+ * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+ * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
+ * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
+ * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGES.
+ */
+
+#include "arla_local.h"
+
+RCSID("$KTH: darla.c,v 1.5 1998/12/21 21:54:03 assar Exp $");
+
+int DARLA_Open(DARLA_file *Dfp, char *fname, int oflag)
+{
+
+ int fd;
+
+ fd = open(fname, oflag);
+ arla_log(ADEBMISC, "DARLA_Open: errno=%d\n", errno);
+ if (fd > 0)
+ {
+ Dfp->fd = fd;
+ Dfp->offset=0;
+ Dfp->log_entries = 0;
+ }
+
+ return fd;
+}
+
+int DARLA_Close(DARLA_file *Dfp)
+{
+ int ret;
+
+ ret = close(Dfp->fd);
+ Dfp->fd = 0;
+ Dfp->offset =0;
+ arla_log(ADEBMISC, "DARLA_Close: ret=%d\n", ret);
+ return ret;
+}
+
+int DARLA_Read(DARLA_file *Dfp, char *cp, int len)
+{
+ ssize_t read_size;
+
+ if (Dfp->fd)
+ {
+ read_size = read (Dfp->fd, cp, len);
+ }
+ else
+ read_size = 0;
+
+ return read_size;
+}
+
+int DARLA_Write(DARLA_file *Dfp, char *cp, int len)
+{
+ ssize_t write_size;
+
+ if (Dfp->fd)
+ {
+ write_size = write(Dfp->fd, cp, len);
+ }
+ else
+ write_size = 0;
+
+ return write_size;
+}
+
+int DARLA_Seek(DARLA_file *Dfp, int offset, int whence)
+{
+
+ off_t lseek_off;
+
+ if (Dfp->fd)
+ {
+ lseek_off = lseek(Dfp->fd, offset, whence);
+ }
+ else
+ lseek_off = 0;
+
+ return lseek_off;
+}
diff --git a/usr.sbin/afs/src/arlad/darla.h b/usr.sbin/afs/src/arlad/darla.h
new file mode 100644
index 00000000000..80853a8c174
--- /dev/null
+++ b/usr.sbin/afs/src/arlad/darla.h
@@ -0,0 +1,51 @@
+/* $OpenBSD: darla.h,v 1.1 1999/04/30 01:59:07 art Exp $ */
+/* COPYRIGHT (C) 1998
+ * THE REGENTS OF THE UNIVERSITY OF MICHIGAN
+ * ALL RIGHTS RESERVED
+ *
+ * PERMISSION IS GRANTED TO USE, COPY, CREATE DERIVATIVE WORKS
+ * AND REDISTRIBUTE THIS SOFTWARE AND SUCH DERIVATIVE WORKS
+ * FOR ANY PURPOSE, SO LONG AS THE NAME OF THE UNIVERSITY OF
+ * MICHIGAN IS NOT USED IN ANY ADVERTISING OR PUBLICITY
+ * PERTAINING TO THE USE OR DISTRIBUTION OF THIS SOFTWARE
+ * WITHOUT SPECIFIC, WRITTEN PRIOR AUTHORIZATION. IF THE
+ * ABOVE COPYRIGHT NOTICE OR ANY OTHER IDENTIFICATION OF THE
+ * UNIVERSITY OF MICHIGAN IS INCLUDED IN ANY COPY OF ANY
+ * PORTION OF THIS SOFTWARE, THEN THE DISCLAIMER BELOW MUST
+ * ALSO BE INCLUDED.
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
+ * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
+ * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
+ * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
+ * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+ * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
+ * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
+ * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGES.
+ */
+
+/* $KTH: darla.h,v 1.3 1998/12/21 21:54:03 assar Exp $ */
+
+#ifndef _DARLA_H
+#define _DARLA_H
+
+#include <lock.h>
+
+typedef struct _DARLA_file {
+ int fd; /*file descriptor of the current file */
+ long offset; /*current byte offset */
+ struct Lock bs_lock; /*lock to synchronize access */
+ long log_entries; /*number of entries */
+} DARLA_file;
+
+int DARLA_Open(DARLA_file *Dfp, char *fname, int oflag);
+int DARLA_Close(DARLA_file *Dfp);
+int DARLA_Read(DARLA_file *Dfp, char *cp, int len);
+int DARLA_Write(DARLA_file *Dfp, char *cp, int len);
+int DARLA_Seek(DARLA_file *Dfp, int offset, int whence);
+
+#endif /* _DARLA_H */
diff --git a/usr.sbin/afs/src/arlad/discon.h b/usr.sbin/afs/src/arlad/discon.h
new file mode 100644
index 00000000000..0d87b28474e
--- /dev/null
+++ b/usr.sbin/afs/src/arlad/discon.h
@@ -0,0 +1,339 @@
+/* $OpenBSD: discon.h,v 1.1 1999/04/30 01:59:07 art Exp $ */
+/* COPYRIGHT (C) 1998
+ * THE REGENTS OF THE UNIVERSITY OF MICHIGAN
+ * ALL RIGHTS RESERVED
+ *
+ * PERMISSION IS GRANTED TO USE, COPY, CREATE DERIVATIVE WORKS
+ * AND REDISTRIBUTE THIS SOFTWARE AND SUCH DERIVATIVE WORKS
+ * FOR ANY PURPOSE, SO LONG AS THE NAME OF THE UNIVERSITY OF
+ * MICHIGAN IS NOT USED IN ANY ADVERTISING OR PUBLICITY
+ * PERTAINING TO THE USE OR DISTRIBUTION OF THIS SOFTWARE
+ * WITHOUT SPECIFIC, WRITTEN PRIOR AUTHORIZATION. IF THE
+ * ABOVE COPYRIGHT NOTICE OR ANY OTHER IDENTIFICATION OF THE
+ * UNIVERSITY OF MICHIGAN IS INCLUDED IN ANY COPY OF ANY
+ * PORTION OF THIS SOFTWARE, THEN THE DISCLAIMER BELOW MUST
+ * ALSO BE INCLUDED.
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
+ * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
+ * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
+ * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
+ * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+ * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
+ * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
+ * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGES.
+ */
+
+/*
+** These are defines for the different type of disconnected
+** operations stored in the log.
+*/
+
+#ifndef _DISCONNH
+#define _DISCONNH
+
+
+/* these are define for integrity checking */
+#define CHECK_SLOTS (long) 0x1
+#define CHECK_LRUQ (long) 0x2
+#define CHECK_FREEVS (long) 0x4
+
+/* values for the dflags in the vcache */
+#define VC_DIRTY 0x01
+#define KEEP_VC 0x04
+#define DBAD_VC 0x08 /* This is a know bad vcache */
+/* this flags is used by GetVSlot to mark when a vcache was read from
+** the disk.
+*/
+#define READ_DISK 0x10
+
+/* Flags for dflags in the fcache */
+#define KEEP_DC 0x01
+
+/* Flags in the afs_VindexFlags */
+
+#define VC_FREE 0x01
+#define HAS_CCORE 0x02
+/* 0x04 is used by KEEP_VC */
+#define VC_DATAMOD 0x08
+#define VC_FLAG 0x10
+#define VC_CLEARAXS 0x20
+#define VC_HAVECB 0x40
+
+/* magic number for data files */
+
+#define AFS_DHMAGIC 0x7635fac1
+
+/* these are the file name extensions for various errors */
+#define STORE_EXT ".store"
+#define RENAME_EXT ".ren"
+#define CREATE_EXT ".creat"
+#define MKDIR_EXT ".mkdir"
+#define LINK_EXT ".link"
+#define SYMLINK_EXT ".slink"
+#define ORPH_EXT ".orph"
+
+/* conflicting defs with arla_local.h */
+/*enum discon_modes {
+ CONNECTED,
+ DISCONNECTED,
+ FETCH_ONLY,
+ PARTIALLY_CONNECTED
+};*/
+
+#define IS_DISCONNECTED(state) (state == DISCONNECTED)
+#define IS_FETCHONLY(state) (state == FETCH_ONLY)
+#define IS_PARTIAL(state) (state == PARTIALLY_CONNECTED)
+#define IS_CONNECTED(state) (state == CONNECTED)
+#define LOG_OPERATIONS(state) ((state == DISCONNECTED) || \
+ (state == FETCH_ONLY) || (state == PARTIALLY_CONNECTED))
+#define USE_OPTIMISTIC(state) ((state == DISCONNECTED) || \
+ (state == FETCH_ONLY))
+
+
+/* These are the different levels of error logging */
+#define DISCON_ERR 0
+#define DISCON_NOTICE 1
+#define DISCON_INFO 2
+#define DISCON_DEBUG 3
+
+/* pioctl flags */
+#define AFS_DIS_RECON 0 /* normal reconnect */
+#define AFS_DIS_DISCON 1 /* disconnect */
+#define AFS_DIS_PANIC 2 /* die, monster devil, die */
+#define AFS_DIS_RECONTOSS 3 /* reconnect now! */
+#define AFS_DIS_QUERY 4 /* query disconnected state */
+#define AFS_DIS_FETCHONLY 5 /* disconnect, fetch-only mode */
+#define AFS_DIS_PARTIAL 6 /* partially connected mode */
+#define AFS_DIS_DISCONTOSS 7 /* disconnect without discarding callbacks */
+
+
+/* these are items defined to fhe PSetDOps */
+
+typedef enum { GET_BACKUP_LOG_NAME,
+ SET_USERLOG_LEVEL,
+ SET_FILELOG_LEVEL,
+ SET_LOGFILE,
+ UPDATE_FLAGS,
+ PING_SERVER,
+ GET_LOG_NAME,
+ GIVEUP_CBS,
+ PRINT_INFO,
+ VERIFY_VCACHE,
+ VERIFY_DCACHE } dis_setopt_op_t;
+
+#if 0
+#define MAX_NAME 255
+#endif
+
+typedef struct dis_setop_info {
+ dis_setopt_op_t op;
+ char data[MAX_NAME];
+} dis_setop_info_t;
+
+
+#ifdef KERNEL
+
+
+#define CELL_DIRTY 0x01
+#define REALLY_BIG 1024
+
+struct save_cell {
+ long cell; /* unique id assigned by venus */
+ char cellName[MAX_NAME]; /* char string name of cell */
+ short cellHosts[MAXHOSTS]; /* volume *location* hosts for this cell */
+ short lcell; /* Associated linked cell */
+ short states; /* state flags */
+ long fsport; /* file server port */
+ long vlport; /* volume server port */
+ short cellIndex; /* relative index number per cell */
+ short dindex; /* disconnected index */
+};
+
+#define SERV_DIRTY 0x01
+
+struct save_server {
+ unsigned int cell; /* cell in which this host resides */
+ long host; /* in network byte order, except subsys */
+ long portal; /* in network byte order */
+ unsigned int random; /* server priority, used for randomizing requests */
+ char isDown; /* result of decision if server is down. */
+ char vcbCount; /* count of vcbs */
+ short dindex; /* disconnected index */
+};
+
+
+#define VOL_DIRTY 0x01
+
+struct save_volume {
+ long cell; /* the cell in which the volume resides */
+ long volume; /* This volume's ID number. */
+ char name[MAX_NAME]; /* This volume's name, or 0 if unknown */
+ short serverHost[MAXHOSTS]; /* servers serving this volume */
+ struct VenusFid dotdot; /* dir to access as .. */
+ struct VenusFid mtpoint; /* The mount point for this volume. */
+ long rootVnode, rootUnique; /* Volume's root fid */
+ long roVol;
+ long backVol;
+ long rwVol; /* For r/o vols, original read/write volume. */
+ long accessTime; /* last time we used it */
+ long copyDate; /* copyDate field, for tracking vol releases */
+ char states; /* snuck here for alignment reasons */
+ short dindex;
+};
+
+
+#define LLIST_SIZE 1024
+
+
+#ifndef GET_WRITE
+#define GET_WRITE 0x1
+#define GET_READ 0x2
+#define GET_SHARED 0x4
+
+#define REL_WRITE 0x10
+#define REL_READ 0x20
+#define REL_SHARED 0x40
+
+#define S_TO_W 0x100
+#define W_TO_S 0x200
+#define W_TO_R 0x400
+#define S_TO_R 0x800
+#endif /* GET_WRITE */
+
+struct llist {
+ struct afs_lock *lk;
+ short operation;
+ short who;
+ struct llist * next;
+ struct llist *prev;
+};
+
+/* These are definition for the translation flags fields */
+
+#define KNOWNBAD 0x20
+#define SYMLINK 0x40
+struct name_trans {
+ struct VenusFid pfid;
+ int ntrans_idx;
+ int oname_idx;
+ int nname_idx;
+ int next_nt_idx;
+ char *old_name;
+ char *new_name;
+ struct name_trans *next;
+};
+
+struct translations {
+ struct VenusFid oldfid;
+ struct VenusFid newfid;
+ u_long flags;
+ hyper validDV;
+ int trans_idx;
+ long callback;
+ long cbExpires;
+ int nl_idx;
+ struct translations *next;
+ struct name_trans *name_list;
+};
+
+
+
+/*
+ * this struct is used to help speed up finding the number of callbacks for
+ * each server
+ */
+
+struct serv_cbcount {
+ long server;
+ long count;
+ struct serv_cbcount *next;
+};
+
+/* Stuff for the link name persistence */
+
+#define MAP_ENTS 100
+#define NAME_UNIT 255
+#define NAME_DIRTY 0x1
+
+/* header for the name backing file */
+typedef struct map_header {
+ long magic; /* magic number */
+ int num_ents; /* number of names stored */
+ char flags; /* flags for in core copy */
+} map_header_t;
+
+/* commented out */
+/*
+ * this struct holds all the information pertaining to a certain
+ * backing store used to keep persistance information
+ */
+/*typedef struct backing_store {
+ long bs_inode;
+ struct osi_dev bs_dev;
+ char *bs_name;
+ map_header_t *bs_header;
+ char *bs_map;
+ struct afs_lock bs_lock;
+ struct osi_file *tfile;
+} backing_store_t;*/
+
+#endif /* KERNEL */
+
+/* CacheItems file has a header of type struct afs_fheader (keep aligned properly) */
+struct afs_dheader {
+ long magic;
+ long firstCSize;
+ long otherCSize;
+ long spare;
+ long current_op;
+ enum connected_mode mode;
+};
+
+#ifdef KERNEL
+
+#define have_shared_lock(lock) \
+ ((((lock)->excl_locked==SHARED_LOCK) && \
+ ((lock)->proc == osi_curpid())) ? 1 : 0)
+
+#define have_write_lock(lock) \
+ ((((lock)->excl_locked==WRITE_LOCK) && \
+ ((lock)->proc == osi_curpid())) ? 1 : 0)
+
+extern struct llist *llist;
+extern struct llist *cur_llist;
+
+/* these are function declarations so I can compile with -Wall in gcc,
+ * not really needed, but help make clean compiles.
+ */
+
+extern int strlen();
+#ifndef AFS_NETBSD_ENV
+extern void strcpy();
+#endif /* AFS_NETBSD_ENV */
+extern void bcopy();
+extern int dir_Delete();
+extern int dir_FindBlobs();
+extern int dir_Lookup();
+extern int dir_Create();
+extern int find_file_name();
+extern int afs_create();
+extern int afs_PutDCache();
+
+#endif /* KERNEL */
+
+#endif /* _DISCONNH */
+
+
+#ifdef DISCONN
+typedef struct _fid_cb {
+VenusFid fid;
+struct _fid_cb *next;
+} fid_cb;
+#endif
+
+
diff --git a/usr.sbin/afs/src/arlad/discon_log.c b/usr.sbin/afs/src/arlad/discon_log.c
new file mode 100644
index 00000000000..b895067a6d4
--- /dev/null
+++ b/usr.sbin/afs/src/arlad/discon_log.c
@@ -0,0 +1,480 @@
+/* $OpenBSD: discon_log.c,v 1.1 1999/04/30 01:59:07 art Exp $ */
+/* COPYRIGHT (C) 1998
+ * THE REGENTS OF THE UNIVERSITY OF MICHIGAN
+ * ALL RIGHTS RESERVED
+ *
+ * PERMISSION IS GRANTED TO USE, COPY, CREATE DERIVATIVE WORKS
+ * AND REDISTRIBUTE THIS SOFTWARE AND SUCH DERIVATIVE WORKS
+ * FOR ANY PURPOSE, SO LONG AS THE NAME OF THE UNIVERSITY OF
+ * MICHIGAN IS NOT USED IN ANY ADVERTISING OR PUBLICITY
+ * PERTAINING TO THE USE OR DISTRIBUTION OF THIS SOFTWARE
+ * WITHOUT SPECIFIC, WRITTEN PRIOR AUTHORIZATION. IF THE
+ * ABOVE COPYRIGHT NOTICE OR ANY OTHER IDENTIFICATION OF THE
+ * UNIVERSITY OF MICHIGAN IS INCLUDED IN ANY COPY OF ANY
+ * PORTION OF THIS SOFTWARE, THEN THE DISCLAIMER BELOW MUST
+ * ALSO BE INCLUDED.
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
+ * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
+ * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
+ * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
+ * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+ * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
+ * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
+ * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGES.
+ */
+
+/*
+ * This file contains functions that relate to performance statistics
+ * for disconnected operation.
+ */
+
+#include "arla_local.h"
+
+RCSID("$KTH: discon_log.c,v 1.8 1998/12/21 21:54:03 assar Exp $");
+
+extern int dlog_mod;
+extern long current_op_no;
+
+extern DARLA_file log_data;
+
+extern long Log_is_open;
+
+log_ent_t log_head;
+
+int DARLA_Open(DARLA_file *Dfp, char *fname, int oflag);
+int DARLA_Read(DARLA_file *Dfp, char *cp, int len);
+int DARLA_Write(DARLA_file *Dfp, char *cp, int len);
+int DARLA_Seek(DARLA_file *Dfp, int offset, int whence);
+
+/*
+ * read an entry from the log file described by tfile. The result is
+ * put into the log_ent data. This return 0 if successful, 1 if
+ * it failed to some reason ( ie. no more data ).
+ */
+
+int
+read_log_ent(DARLA_file * tfile, log_ent_t *in_log)
+{
+ int len;
+ char *bp;
+
+ if (DARLA_Read(tfile, (char *) in_log, sizeof (int)) != sizeof(int))
+ return 1;
+
+ len = in_log->log_len - sizeof(int);
+ bp = (char *) in_log + sizeof(int);
+
+ if (DARLA_Read(tfile, bp, len) != len) {
+ printf("read_log_ent: short read \n");
+ return 1;
+ }
+ return 0;
+}
+
+#if 0
+void
+update_log_ent(offset, flags)
+long offset;
+int flags;
+{
+ struct DARLA_file *tfile;
+ log_ent_t *log_ent;
+ int code;
+
+ tfile = DARLA_UFSOpen(&log_data.bs_dev, log_data.bs_inode);
+ if (!tfile)
+ panic("update_log_ent: failed to open log file");
+
+ DARLA_Seek(tfile, offset);
+
+ log_ent = (log_ent_t *) malloc(sizeof(log_ent_t));
+ code = read_log_ent(tfile, log_ent);
+
+ if (code) {
+ printf("update_log_ent: failed to read log entry at %d \n",
+ offset);
+ } else {
+
+ /* set the log flags */
+ log_ent->log_flags |= flags;
+
+ /* write the entry back out */
+ DARLA_Seek(tfile, offset);
+ DARLA_Write(tfile, (char *) log_ent, log_ent->log_len);
+ }
+ free(log_ent);
+ DARLA_Close(tfile);
+}
+#endif
+
+
+/* write the log entries to disk */
+long
+write_log_ent(int len, log_ent_t *log)
+{
+
+ long new_num;
+ static int index=0;
+
+ arla_warnx (ADEBDISCONN,"We are writing a log");
+ if (!Log_is_open) {
+ return -1;
+ }
+
+ if (log_head.next == 0) {
+ log_head.next = (log_ent_t *) malloc(sizeof(log_ent_t));
+ *log_head.next = *log;
+ log_head.next->next = 0;
+ }
+ else {
+ log->next = log_head.next;
+ log_head.next = (log_ent_t *) malloc(sizeof(log_ent_t));
+ *log_head.next = *log;
+ }
+
+ ObtainWriteLock(&log_data.bs_lock);
+
+ new_num = 0;
+
+ log->log_opno = new_num;
+ gettimeofday(&log->log_time, 0);
+
+ log->log_offset = log_data.offset;
+ log->log_flags = 0;
+ log->log_index = index++;
+
+ DARLA_Write(&log_data, (char *) log, len);
+
+ ReleaseWriteLock(&log_data.bs_lock);
+
+ return (new_num);
+}
+
+long
+log_dis_store(struct vcache *avc)
+{
+ log_ent_t *store;
+ long op_no;
+
+ store = (log_ent_t *) malloc(sizeof(log_ent_t));
+
+ store->log_op = DIS_STORE;
+ store->st_fid = avc->fid;
+ store->st_origdv = avc->DataVersion;
+ store->st_flag = avc->flag;
+
+ /* have to log cred as well */
+ store->cred = avc->cred;
+
+ /* figure out the length of a store entry */
+ store->log_len = ((char *) &(store->st_origdv)) - ((char *) store)
+ + sizeof(store->st_origdv);
+
+ op_no = write_log_ent(store->log_len, store);
+
+ free(store);
+ return op_no;
+}
+
+
+/* Log a mkdir operation */
+long
+log_dis_mkdir(struct vcache *pvc, struct vcache *dvc,
+ AFSStoreStatus *attrs, char *name)
+{
+ log_ent_t *mkdir;
+ long op_no;
+
+ mkdir = (log_ent_t *) malloc(sizeof(log_ent_t));
+
+ mkdir->log_op = DIS_MKDIR;
+ mkdir->md_dirfid = dvc->fid;
+ /*Ba Wu: the data vers. for child dir*/
+ mkdir->md_dversion = dvc->DataVersion;
+ mkdir->md_parentfid = pvc->fid;
+ mkdir->cred = pvc->cred;
+ mkdir->md_vattr = *attrs;
+
+ /* save the name */
+ strcpy((char *) mkdir->md_name, name);
+
+ /* calculate the length of this record */
+ mkdir->log_len = ((char *) mkdir->md_name - (char *) mkdir)
+ + strlen(name) + 1;
+
+ op_no = write_log_ent(mkdir->log_len, mkdir);
+
+ free(mkdir);
+ return op_no;
+}
+
+
+long
+log_dis_create(struct vcache *parent, struct vcache *child, char *name)
+{
+ log_ent_t *create;
+ long op_no;
+ struct vcache *ch;
+ struct vcache *par;
+
+ ch = child;
+ par = parent;
+ ch->DataVersion = child->DataVersion;
+
+ create = (log_ent_t *) malloc(sizeof(log_ent_t));
+
+ create->log_op = DIS_CREATE;
+ create->cr_filefid = ch->fid;
+ create->cr_parentfid = par->fid;
+ create->cr_origdv = ch->DataVersion;
+ create->cred = parent->cred;
+
+ strcpy((char *) create->cr_name, name);
+
+ create->log_len = ((char *) create->cr_name - (char *) create) +
+ strlen(name) + 1;
+
+ op_no = write_log_ent(create->log_len, create);
+
+ free(create);
+ return op_no;
+}
+
+long
+log_dis_remove(struct vcache *avc, FCacheEntry *childentry, char *name)
+{
+ log_ent_t *remove;
+ long op_no;
+ remove = (log_ent_t *) malloc(sizeof(log_ent_t));
+
+ remove->log_op = DIS_REMOVE;
+ remove->cred = avc->cred;
+ remove->rm_filefid = avc->fid;
+ remove->rm_origdv = avc->DataVersion;
+ remove->rm_chentry = childentry;
+
+ strcpy((char *) remove->rm_name, name);
+
+ remove->log_len = ((char *) remove->rm_name - (char *) remove) +
+ strlen(name) + 1;
+
+ op_no = write_log_ent(remove->log_len, remove);
+
+ free(remove);
+ arla_log(ADEBDISCONN, "remove: fid.Cell=%ld, fid.fid.Volume=%ld, "
+ "fid.Unique=%ld", \
+ remove->rm_filefid.Cell,
+ remove->rm_filefid.fid.Volume,
+ remove->rm_filefid.fid.Unique);
+
+ return op_no;
+}
+
+
+long
+log_dis_rmdir(struct vcache *dir, FCacheEntry *cce, const char *name)
+{
+ log_ent_t *rmdir;
+ long op_no;
+
+ rmdir = malloc(sizeof(log_ent_t));
+
+ rmdir->log_op = DIS_RMDIR;
+ rmdir->cred = dir->cred;
+ rmdir->rd_parentfid = dir->fid;
+ rmdir->rd_direntry = cce;
+
+ strcpy((char *) rmdir->rd_name, name);
+
+ rmdir->log_len = ((char *) rmdir->rd_name - (char *) rmdir) +
+ strlen(name) + 1;
+
+ op_no = write_log_ent(rmdir->log_len, rmdir);
+
+ free(rmdir);
+ return op_no;
+}
+
+
+long
+log_dis_rename(struct vcache *old_dir, char *old_name,
+ struct vcache *new_dir, char *new_name)
+{
+ log_ent_t *rename;
+ char *cp;
+
+ rename = malloc(sizeof(log_ent_t));
+
+ rename->log_op = DIS_RENAME;
+ rename->rn_oparentfid = old_dir->fid;
+ rename->rn_nparentfid = new_dir->fid;
+ rename->rn_origdv = old_dir->DataVersion;
+ rename->rn_overdv = new_dir->DataVersion;
+ rename->cred = old_dir->cred;
+
+ strcpy((char *) rename->rn_names, old_name);
+ cp = (char *) rename->rn_names + strlen(old_name) + 1;
+
+ strcpy((char *) cp, new_name);
+ cp += strlen(new_name) + 1;
+
+ rename->log_len = (char *) cp - (char *) rename;
+
+ write_log_ent(rename->log_len, rename);
+
+ free(rename);
+ return 0;
+}
+
+
+
+/* Log a link operation */
+long
+log_dis_link(struct vcache *pvc, struct vcache *lvc, char *name)
+
+{
+ log_ent_t *link;
+ long op_no;
+
+ link = malloc(sizeof(log_ent_t));
+
+ link->log_op = DIS_LINK;
+ link->cred = pvc->cred;
+ link->ln_linkfid = lvc->fid;
+ link->ln_parentfid = pvc->fid;
+
+ /* save the name */
+ strcpy((char *) link->ln_name, name);
+ /* calculate the length of this record */
+ link->log_len = ((char *) link->ln_name - (char *) link) +
+ strlen(name) + 1;
+
+ op_no = write_log_ent(link->log_len, link);
+
+ free(link);
+ return op_no;
+}
+
+/* Log a symlink operation */
+long
+log_dis_symlink(struct vcache *pvc, struct vcache *cvc,
+ AFSStoreStatus *attr, char *linkname, char *content)
+{
+ log_ent_t *slink;
+ long op_no;
+
+ slink = malloc(sizeof(log_ent_t));
+
+ slink->log_op = DIS_SYMLINK;
+ slink->sy_parentfid = pvc->fid;
+ slink->sy_filefid = cvc->fid;
+ slink->sy_attr = *attr;
+ slink->cred = pvc->cred;
+
+ /* copy in the link name */
+ strcpy((char *) slink->sy_name, linkname);
+ strcpy((char *) slink->sy_content, content);
+
+ /* calculate the length of this record */
+ slink->log_len = ( (char *) slink->sy_content -
+ (char *) slink) +
+ strlen(content) + 1;
+
+ op_no = write_log_ent(slink->log_len, slink);
+
+ free(slink);
+ return op_no;
+}
+
+
+/* Log a setattr operation */
+long
+log_dis_setattr(struct vcache *tvc, struct xfs_attr *attrs)
+{
+ log_ent_t *setattr;
+ long op_no;
+
+ setattr = (log_ent_t *) malloc(sizeof(log_ent_t));
+
+ setattr->log_op = DIS_SETATTR;
+ setattr->sa_fid = tvc->fid;
+ setattr->cred = tvc->cred;
+ setattr->sa_origdv = tvc->DataVersion;
+
+ setattr->sa_vattr = *attrs;
+
+ /* calculate the length of this record */
+ setattr->log_len = ((char *) &setattr->sa_origdv - (char *) setattr) +
+ sizeof(setattr->sa_origdv);
+
+ op_no = write_log_ent(setattr->log_len, setattr);
+
+ arla_log(ADEBDISCONN, "log_dis_setattr: fid.Cell=0x%x, fid.fid.Volume=0x%x,"
+ "fid.fid.Vnode=0x%x, fid.fid.Unique=0x%x",
+ tvc->fid.Cell,
+ tvc->fid.fid.Volume,
+ tvc->fid.fid.Vnode,
+ tvc->fid.fid.Unique);
+
+ arla_log(ADEBDISCONN, "log_dis_setattr: writing %d byte log entry.");
+
+ free(setattr);
+ return op_no;
+}
+
+long
+log_dis_nonmutating(struct vcache *tvc, log_ops_t op)
+{
+#ifdef LOGNONMUTE
+ log_ent_t *non_mute;
+ long op_no;
+
+ non_mute = (log_ent_t *) malloc(sizeof(log_ent_t));
+
+ non_mute->log_op = op;
+ non_mute->cred = tvc->cred;
+ non_mute->nm_fid = tvc->fid;
+ non_mute->nm_origdv = tvc->DataVersion;
+ non_mute->log_len = ((char *) &non_mute->nm_origdv -
+ (char *) non_mute) + sizeof(non_mute->nm_origdv);
+
+ /* XXX lhuston removed for debugging */
+ op_no = write_log_ent(non_mute->log_len, non_mute);
+
+ free(non_mute);
+ return op_no;
+#else
+ return 0; /* 0 was current_op_no */
+#endif
+}
+
+
+long
+log_dis_access(struct vcache *tvc)
+{
+ return log_dis_nonmutating(tvc, DIS_ACCESS);
+}
+
+long
+log_dis_readdir(struct vcache *tvc)
+{
+ return log_dis_nonmutating(tvc, DIS_READDIR);
+}
+
+long
+log_dis_readlink(struct vcache *tvc)
+{
+ return log_dis_nonmutating(tvc, DIS_READLINK);
+}
+
+long
+log_dis_fsync(struct vcache *tvc)
+{
+ /* treat an fsync as a store */
+ return log_dis_nonmutating(tvc, DIS_FSYNC);
+}
diff --git a/usr.sbin/afs/src/arlad/discon_log.h b/usr.sbin/afs/src/arlad/discon_log.h
new file mode 100644
index 00000000000..2fdb2a6ef94
--- /dev/null
+++ b/usr.sbin/afs/src/arlad/discon_log.h
@@ -0,0 +1,268 @@
+/* $OpenBSD: discon_log.h,v 1.1 1999/04/30 01:59:07 art Exp $ */
+/* COPYRIGHT (C) 1998
+ * THE REGENTS OF THE UNIVERSITY OF MICHIGAN
+ * ALL RIGHTS RESERVED
+ *
+ * PERMISSION IS GRANTED TO USE, COPY, CREATE DERIVATIVE WORKS
+ * AND REDISTRIBUTE THIS SOFTWARE AND SUCH DERIVATIVE WORKS
+ * FOR ANY PURPOSE, SO LONG AS THE NAME OF THE UNIVERSITY OF
+ * MICHIGAN IS NOT USED IN ANY ADVERTISING OR PUBLICITY
+ * PERTAINING TO THE USE OR DISTRIBUTION OF THIS SOFTWARE
+ * WITHOUT SPECIFIC, WRITTEN PRIOR AUTHORIZATION. IF THE
+ * ABOVE COPYRIGHT NOTICE OR ANY OTHER IDENTIFICATION OF THE
+ * UNIVERSITY OF MICHIGAN IS INCLUDED IN ANY COPY OF ANY
+ * PORTION OF THIS SOFTWARE, THEN THE DISCLAIMER BELOW MUST
+ * ALSO BE INCLUDED.
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
+ * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
+ * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
+ * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
+ * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+ * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
+ * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
+ * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGES.
+ */
+
+/*
+ * This file contains all the relevant information pertaining to logging
+ * for disconnected afs.
+ */
+/* replace vattr with xfs_attr in the log */
+#include <xfs/xfs_attr.h>
+#ifndef _DISCONN_LOG_H
+
+#define _DISCONN_LOG_H
+
+#define BUFSIZE 256
+
+#define MAX_NAME AFSNAMEMAX
+
+enum log_ops {
+ DIS_STORE,
+ DIS_MKDIR,
+ DIS_CREATE,
+ DIS_REMOVE,
+ DIS_RMDIR,
+ DIS_RENAME,
+ DIS_LINK,
+ DIS_SYMLINK,
+ DIS_SETATTR,
+ DIS_FSYNC,
+ DIS_ACCESS,
+ DIS_READDIR,
+ DIS_READLINK,
+ DIS_INFO,
+ DIS_START_OPT,
+ DIS_END_OPT,
+ DIS_REPLAYED
+};
+
+typedef enum log_ops log_ops_t;
+
+/* These are defines for the different log flags that can be set */
+#define LOG_INACTIVE 0x1 /* log no longer needs replay */
+#define LOG_REPLAYED 0x2 /* log entry was replayed */
+#define LOG_OPTIMIZED 0x4 /* log entry was optimized away */
+#define LOG_GENERATED 0x8 /* log entry created by optimizer */
+
+
+/* defines to make access easier */
+#define st_fid log_data.st.fid
+#define st_origdv log_data.st.origdv
+
+/* added flag option */
+#define st_flag log_data.st.flag
+
+typedef u_int32_t hyper;
+
+/* a really stripped down version of CITI's vcache */
+struct vcache {
+ u_int32_t DataVersion;
+ struct VenusFid fid;
+ xfs_cred cred;
+ u_int flag; /* write flag */
+};
+
+typedef struct store_log_data {
+ struct VenusFid fid; /* fid of the file */
+ u_int flag; /* write flag */
+ hyper origdv; /* cached data version of file */
+} store_log_data_t;
+
+/* defines to make access easier */
+#define md_dirfid log_data.md.dirfid
+#define md_parentfid log_data.md.parentfid
+#define md_vattr log_data.md.vattr
+#define md_dversion log_data.md.dversion
+#define md_name log_data.md.name
+
+typedef struct mkdir_log_data {
+ struct VenusFid dirfid; /* Fid of this dir */
+ struct VenusFid parentfid; /* Fid of parent */
+ /* struct vattr vattr; attrs to create with */
+ AFSStoreStatus vattr; /* log store_status */ /*Ba Wu */
+ hyper dversion; /* cached data version of file */
+ char name[MAX_NAME]; /* space to store create name */
+} mkdir_log_data_t;
+
+
+/* defines to make access easier */
+#define cr_filefid log_data.cr.filefid
+#define cr_parentfid log_data.cr.parentfid
+#define cr_vattr log_data.cr.vattr
+#define cr_mode log_data.cr.mode
+#define cr_exists log_data.cr.exists
+#define cr_excl log_data.cr.excl
+#define cr_origdv log_data.cr.origdv
+#define cr_name log_data.cr.name
+
+typedef struct create_log_data {
+ struct VenusFid filefid; /* Fid of this file */
+ struct VenusFid parentfid; /* Fid of parent */
+ struct xfs_attr vattr; /* attrs to create with */
+ int mode; /* mode to create with */
+ int exists; /* did file exists */
+ int excl; /* is file create exclusive ? */
+ hyper origdv; /* cached data version of file */
+ char name[MAX_NAME]; /* space to store create name */
+} create_log_data_t;
+
+
+
+
+/* defines to make access easier */
+#define rm_filefid log_data.rm.filefid
+#define rm_chentry log_data.rm.chentry
+#define rm_origdv log_data.rm.origdv
+#define rm_name log_data.rm.name
+
+typedef struct remove_log_data {
+ struct VenusFid filefid; /* Fid of this file */
+ /*struct VenusFid parentfid;*/ /* Fid of parent */
+ FCacheEntry *chentry; /*The entry for the deleted file*/
+ hyper origdv; /* cached data version of file */
+ char name[MAX_NAME]; /* space to store remove name */
+} remove_log_data_t;
+
+
+
+/* defines to make access easier */
+#define rd_direntry log_data.rd.direntry
+#define rd_parentfid log_data.rd.parentfid
+#define rd_name log_data.rd.name
+
+typedef struct rmdir_log_data {
+ FCacheEntry *direntry; /*Entry of this dir */
+ struct VenusFid parentfid; /* Fid of parent */
+ char name[MAX_NAME]; /* space to store dir name */
+} rmdir_log_data_t;
+
+
+/* defines to make access easier */
+#define rn_oparentfid log_data.rn.oparentfid
+#define rn_nparentfid log_data.rn.nparentfid
+#define rn_renamefid log_data.rn.renamefid
+#define rn_overfid log_data.rn.overfid
+#define rn_origdv log_data.rn.origdv
+#define rn_overdv log_data.rn.overdv
+#define rn_names log_data.rn.names
+
+typedef struct rename_log_data {
+ struct VenusFid oparentfid; /* Fid of parent */
+ struct VenusFid nparentfid; /* Fid of parent */
+ struct VenusFid renamefid; /* Fid of file being rename */
+ struct VenusFid overfid; /* Fid of overwritten file */
+ hyper origdv; /* cached data version of file */
+ hyper overdv; /* overwritten version of cached data */
+ char names[MAX_NAME * 2]; /* space to store dir name */
+} rename_log_data_t;
+
+/* defines to make access easier */
+#define ln_linkfid log_data.ln.linkfid
+#define ln_parentfid log_data.ln.parentfid
+#define ln_name log_data.ln.name
+
+typedef struct link_log_data {
+ struct VenusFid linkfid; /* Fid of this dir */
+ struct VenusFid parentfid; /* Fid of parent */
+ char name[MAX_NAME]; /* space to store create name */
+} link_log_data_t;
+
+/* defines to make access easier */
+#define sy_linkfid log_data.sy.linkfid
+#define sy_parentfid log_data.sy.parentfid
+#define sy_filefid log_data.sy.filefid
+#define sy_attr log_data.sy.attr
+#define sy_name log_data.sy.name
+#define sy_content log_data.sy.content
+
+
+typedef struct slink_log_data {
+ struct VenusFid linkfid; /* Fid of this link */
+ struct VenusFid parentfid; /* Fid of parent */
+ struct VenusFid filefid; /* Fid of file */
+ AFSStoreStatus attr; /* attrs to create with */
+ char name[MAX_NAME]; /* space to name */
+ char content[MAX_NAME]; /* space to new name */
+} slink_log_data_t;
+
+/* defines to make access easier */
+#define sa_fid log_data.sa.fid
+#define sa_vattr log_data.sa.vattr
+#define sa_origdv log_data.sa.origdv
+
+typedef struct setattr_log_data {
+ struct VenusFid fid; /* operand fid */
+ struct xfs_attr vattr; /* attrs to set */
+ hyper origdv; /* cached data version number */
+} setattr_log_data_t;
+
+
+/* defines to make access easier */
+#define nm_fid log_data.nm.fid
+#define nm_origdv log_data.nm.origdv
+
+typedef struct nonmute_log_data {
+ struct VenusFid fid; /* fid */
+ hyper origdv; /* cached data version */
+} nonmute_log_data_t;
+
+
+
+typedef struct log_ent {
+ int log_len; /* len of this entry */
+ log_ops_t log_op; /* operation */
+ long log_opno; /* operation number */
+ struct timeval log_time; /* time operation was logged */
+ long log_offset; /* offset into the log file */
+ short log_flags; /* offset into the log file */
+ uid_t log_uid; /* uid of person performing op */
+ xfs_cred cred; /* user credential */
+ int log_index; /* index for the log */
+ struct log_ent *next; /* point to the next one */
+
+ union {
+ store_log_data_t st;
+ mkdir_log_data_t md;
+ create_log_data_t cr;
+ remove_log_data_t rm;
+ rmdir_log_data_t rd;
+ rename_log_data_t rn;
+ link_log_data_t ln;
+ slink_log_data_t sy;
+ setattr_log_data_t sa;
+ nonmute_log_data_t nm;
+ } log_data;
+} log_ent_t;
+
+
+long log_dis_create(struct vcache *parent, struct vcache *child, char *name);
+
+
+#endif /* _DISCONN_LOG_H */
+
diff --git a/usr.sbin/afs/src/arlad/fs_errors.h b/usr.sbin/afs/src/arlad/fs_errors.h
new file mode 100644
index 00000000000..8a4695d4416
--- /dev/null
+++ b/usr.sbin/afs/src/arlad/fs_errors.h
@@ -0,0 +1,92 @@
+/* $OpenBSD: fs_errors.h,v 1.1 1999/04/30 01:59:08 art Exp $ */
+/*
+ * Copyright (c) 1998, 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the Kungliga Tekniska
+ * Högskolan and its contributors.
+ *
+ * 4. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _FS_ERRORS_H_
+#define _FS_ERRORS_H_ 1
+
+#define VICE_SPECIAL_ERRORS 101
+
+#define VICE_SPECIAL_ERRORS_MIN 101
+#define VICE_SPECIAL_ERRORS_MAX 112
+
+#define VSALVAGE 101
+#define VNOVNODE 102
+#define VNOVOL 103
+#define VVOLEXISTS 104
+#define VNOSERVICE 105
+#define VOFFLINE 106
+#define VONLINE 107
+#define VDISKFULL 108
+#define VOVERQUOTA 109
+#define VBUSY 110
+#define VMOVED 111
+#define VIO 112
+
+#define VRESTARTING -100
+
+#define ARLA_SPECIAL_ERROR_ADD 4000
+#define ARLA_SPECIAL2_ERROR_ADD 4600
+
+#define ARLA_VSALVAGE (ARLA_SPECIAL_ERROR_ADD+VSALVAGE)
+#define ARLA_VNOVNODE (ARLA_SPECIAL_ERROR_ADD+VNOVNODE)
+#define ARLA_VNOVOL (ARLA_SPECIAL_ERROR_ADD+VNOVOL)
+#define ARLA_VVOLEXISTS (ARLA_SPECIAL_ERROR_ADD+VVOLEXISTS)
+#define ARLA_VNOSERVICE (ARLA_SPECIAL_ERROR_ADD+VNOSERVICE)
+#define ARLA_VOFFLINE (ARLA_SPECIAL_ERROR_ADD+VOFFLINE)
+#define ARLA_VONLINE (ARLA_SPECIAL_ERROR_ADD+VONLINE)
+#define ARLA_VDISKFULL (ARLA_SPECIAL_ERROR_ADD+VDISKFULL)
+#define ARLA_VOVERQUOTA (ARLA_SPECIAL_ERROR_ADD+VOVERQUOTA)
+#define ARLA_VBUSY (ARLA_SPECIAL_ERROR_ADD+VBUSY)
+#define ARLA_VMOVED (ARLA_SPECIAL_ERROR_ADD+VMOVED)
+#define ARLA_VIO (ARLA_SPECIAL_ERROR_ADD+VIO)
+#define ARLA_VRESTARTING (ARLA_SPECIAL2_ERROR_ADD+VRESTARTING)
+
+static inline int __attribute__ ((unused))
+conv_to_arla_errno(int error)
+{
+ if (error >= VICE_SPECIAL_ERRORS_MIN &&
+ error <= VICE_SPECIAL_ERRORS_MAX)
+ return error + ARLA_SPECIAL_ERROR_ADD;
+ else if (error == VRESTARTING)
+ return ARLA_VRESTARTING;
+ else
+ return error;
+}
+
+#endif /* _FS_ERRORS_H_ */
diff --git a/usr.sbin/afs/src/arlad/reconnect.c b/usr.sbin/afs/src/arlad/reconnect.c
new file mode 100644
index 00000000000..bebb4b82e41
--- /dev/null
+++ b/usr.sbin/afs/src/arlad/reconnect.c
@@ -0,0 +1,2172 @@
+/* $OpenBSD: reconnect.c,v 1.1 1999/04/30 01:59:10 art Exp $ */
+/* COPYRIGHT (C) 1998
+ * THE REGENTS OF THE UNIVERSITY OF MICHIGAN
+ * ALL RIGHTS RESERVED
+ *
+ * PERMISSION IS GRANTED TO USE, COPY, CREATE DERIVATIVE WORKS
+ * AND REDISTRIBUTE THIS SOFTWARE AND SUCH DERIVATIVE WORKS
+ * FOR ANY PURPOSE, SO LONG AS THE NAME OF THE UNIVERSITY OF
+ * MICHIGAN IS NOT USED IN ANY ADVERTISING OR PUBLICITY
+ * PERTAINING TO THE USE OR DISTRIBUTION OF THIS SOFTWARE
+ * WITHOUT SPECIFIC, WRITTEN PRIOR AUTHORIZATION. IF THE
+ * ABOVE COPYRIGHT NOTICE OR ANY OTHER IDENTIFICATION OF THE
+ * UNIVERSITY OF MICHIGAN IS INCLUDED IN ANY COPY OF ANY
+ * PORTION OF THIS SOFTWARE, THEN THE DISCLAIMER BELOW MUST
+ * ALSO BE INCLUDED.
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
+ * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
+ * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
+ * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
+ * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+ * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
+ * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
+ * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGES.
+ */
+
+/*
+ * Do merging of the files that changed with we was in disconnected mode
+ */
+
+#include "arla_local.h"
+
+RCSID("$KTH: reconnect.c,v 1.11 1999/02/15 04:49:43 art Exp $");
+
+static int reconnect_nonmute(struct vcache *, int, struct timeval);
+static int reconnect_putattr(struct vcache *, struct xfs_attr *);
+static int reconnect_putdata(struct vcache *);
+static int reconnect_remove(struct vcache *, FCacheEntry *childentry, char *);
+static int reconnect_rename(struct vcache *, struct vcache *, char *, char *);
+static int reconnect_rmdir(struct vcache *vcp, FCacheEntry *childEntry,
+ char *name);
+static int reconnect_mkdir(struct vcache *parent, struct vcache *curdir,
+ AFSStoreStatus *store_status, char *name);
+static int reconnect_link(struct vcache *parent, struct vcache *existing,
+ char *name);
+static int reconnect_symlink(struct vcache *parent, struct vcache *child,
+ AFSStoreStatus *store_attr, char *name,
+ char *contents);
+static int reconnect_create(struct vcache *parent, struct vcache *child,
+ char *name);
+static int reconnect_mut_chk(FCacheEntry *fce, CredCacheEntry *ce,
+ int version);
+
+static int check_log_todo(log_ent_t * , VenusFid *, VenusFid *);
+static int is_done_before(int no);
+static void add_done_list(int no);
+static void clear_log_entry(void);
+static void clear_index_list(void);
+
+typedef struct _fid_trans{
+ VenusFid logged_fid;
+ VenusFid fetched_fid;
+ struct _fid_trans *next, *prev;
+} fid_trans;
+
+typedef struct _fid_keep{
+ char name[MAX_NAME];
+ AFSFid kept_fid;
+ struct _fid_keep *next;
+} fid_keep;
+
+typedef struct _index_list{
+ int index;
+ struct _index_list * next;
+} index_list;
+
+fid_trans *fid_AD_head, *fid_AD_tail;
+fid_keep *fid_KP_head;
+index_list * index_head;
+extern log_ent_t log_head;
+
+
+/*
+ *
+ */
+
+static void
+set_fid_value(VenusFid *new, VenusFid *old)
+{
+ if(old==0) {
+ new->fid.Volume = 0;
+ new->fid.Vnode = 0;
+ new->fid.Unique = 0;
+ } else {
+ new->fid.Volume = old->fid.Volume;
+ new->fid.Vnode = old->fid.Vnode;
+ new->fid.Unique = old->fid.Unique;
+ }
+}
+
+/*
+ *
+ */
+
+void
+do_replay(char *log_file, int log_entries, VenusFid *changed_fid)
+{
+ int fd, len, i;
+ log_ent_t *cur_log;
+ struct vcache vc, vc_new;
+ char *name, *name_new;
+ fid_trans *fid_tmp;
+ fid_keep * fid_KP_tail;
+ VenusFid new_fid;
+
+ int count=1; /* Used to record how may actions we have done*/
+
+ fid_AD_tail = fid_AD_head;
+ cur_log = (log_ent_t *) malloc(sizeof(log_ent_t));
+ fd = open(log_file, O_RDONLY | O_BINARY);
+
+ set_fid_value(&new_fid , 0);
+
+ while (read(fd, cur_log, sizeof(int))){
+
+ if (cur_log->log_len < sizeof(*cur_log) - sizeof(cur_log->log_data) ||
+ cur_log->log_len > sizeof(log_ent_t)) {
+ arla_log(ADEBDISCONN, "do_replay: corrupt log entry, log_len %d",
+ cur_log->log_len);
+ goto terminate;
+ }
+
+ len = cur_log->log_len - sizeof(int);
+
+ if (!read(fd, ((char *)cur_log + sizeof(int)), len)){
+ arla_log(ADEBDISCONN, "do_replay: read bad log entry...");
+ goto terminate;
+ }
+
+ arla_log(ADEBDISCONN,
+ "do_replay: read %d bytes of log entry.",
+ cur_log->log_len);
+
+ if (is_done_before(cur_log->log_index)==1)
+ continue; /* the log entry has been executed */
+ else {
+ if (changed_fid !=0) {
+ int is_log_todo = 0;
+
+ is_log_todo = check_log_todo(cur_log, changed_fid, &new_fid);
+ if (is_log_todo ==0)
+ continue; /* This log should not be executed */
+ }
+ }
+
+ add_done_list(cur_log->log_index);
+
+ /* big case/switch statement to switch log_op */
+ switch (cur_log->log_op){
+
+ case DIS_STORE:
+ vc.fid = cur_log->st_fid;
+ vc.DataVersion = cur_log->st_origdv-1;
+ vc.flag = cur_log->st_flag;
+ vc.cred = cur_log->cred;
+ arla_log(ADEBDISCONN,
+ "%d action is to do_replay: **replay** (putdata) op...",
+ count++);
+ reconnect_putdata(&vc);
+ break;
+ case DIS_SETATTR:
+ vc.fid = cur_log->sa_fid;
+ vc.DataVersion = cur_log->sa_origdv;
+ vc.flag = 0;
+ vc.cred = cur_log->cred;
+ arla_log(ADEBDISCONN,
+ "%d action is to do_replay: **replay** (putattr) op...",
+ count++);
+ reconnect_putattr(&vc, &(cur_log->sa_vattr));
+ break;
+ case DIS_REMOVE: {
+ FCacheEntry *childentry;
+ vc.fid = cur_log->rm_filefid;
+ vc.DataVersion = cur_log->rm_origdv;
+ vc.flag = 0;
+ vc.cred = cur_log->cred;
+ childentry = cur_log->rm_chentry;
+ name = cur_log->rm_name;
+ arla_log(ADEBDISCONN,
+ "%d action is to do_replay: **replay** "
+ "(file remove) op...",
+ count++);
+ reconnect_remove(&vc, childentry, name);
+ break;
+ }
+ case DIS_RMDIR: {
+ FCacheEntry *child;
+ vc.fid = cur_log->rd_parentfid;
+ name = cur_log->rd_name;
+ vc.cred = cur_log->cred;
+ child = cur_log->rd_direntry;
+ arla_log (ADEBDISCONN,
+ "%d action is to do_replay: **rmdir** "
+ "(directory remove) op...",
+ count++);
+ reconnect_rmdir(&vc, child, name);
+ break;
+ }
+ case DIS_RENAME:
+ vc.fid = cur_log->rn_oparentfid;
+ vc.DataVersion = cur_log->rn_origdv;
+ vc.flag = 0;
+ vc.cred = cur_log->cred;
+ vc_new.fid = cur_log->rn_nparentfid;
+ vc_new.DataVersion = cur_log->rn_overdv;
+ vc_new.flag = 0;
+ vc_new.cred = cur_log->cred;
+ name = cur_log->rn_names;
+ for (i=0; *(name+i)!='\0';++i);
+ name_new = name+i+1;
+ arla_log(ADEBDISCONN,
+ "%d action is to do_replay: **replay** (rename) op...",
+ count++);
+ reconnect_rename(&vc, &vc_new, name, name_new);
+ break;
+ case DIS_MKDIR: {
+ AFSStoreStatus store_status;
+ vc.fid = cur_log->md_parentfid;
+ vc.cred = cur_log->cred;
+ store_status = cur_log->md_vattr;
+ vc_new.fid = cur_log->md_dirfid;
+ /*Ba Wu: child's data vers*/
+ vc_new.DataVersion = cur_log->md_dversion;
+ name = cur_log->md_name;
+ arla_log(ADEBDISCONN,
+ "%d action is to DO_Replay: **replay** (mkdir) op...",
+ count++);
+ reconnect_mkdir(&vc, &vc_new, &store_status, name);
+ break;
+ }
+ case DIS_LINK:
+ vc.cred = cur_log->cred;
+ vc.fid = cur_log->ln_parentfid;
+ vc_new.fid = cur_log->ln_linkfid;
+ name = cur_log->ln_name;
+ arla_log(ADEBDISCONN,
+ "%d action is to do_replay: **replay** (link) op...",
+ count++);
+ reconnect_link(&vc, &vc_new, name);
+ break;
+ case DIS_SYMLINK: {
+ char *new_name;
+ AFSStoreStatus store_attr;
+
+ vc.fid = cur_log->sy_parentfid;
+ vc.cred = cur_log->cred;
+ name = cur_log->sy_name;
+ new_name = cur_log->sy_content;
+ vc_new.fid = cur_log->sy_filefid;
+ store_attr = cur_log->sy_attr;
+ arla_log(ADEBDISCONN,
+ "%d action is to do_replay: **replay** (symlink) op...",
+ count++);
+ reconnect_symlink(&vc, &vc_new, &store_attr, name, new_name);
+ break;
+ }
+ case DIS_CREATE:
+ vc.fid = cur_log->cr_parentfid;
+ vc.cred = cur_log->cred;
+
+ vc_new.fid = cur_log->cr_filefid;
+ vc_new.DataVersion = cur_log->cr_origdv;
+ arla_log(ADEBDISCONN,
+ "%d action is to DO_Replay: **replay** (create) op...",
+ count++);
+ name = cur_log->cr_name;
+ reconnect_create(&vc, &vc_new, name);
+ break;
+ case DIS_ACCESS:
+ vc.fid = cur_log->nm_fid;
+ vc.DataVersion = cur_log->nm_origdv;
+ vc.cred = cur_log->cred;
+ arla_log(ADEBDISCONN,
+ "%d action is to do_replay: **replay** (nonmutating) op",
+ count++);
+ reconnect_nonmute(&vc, cur_log->log_op, cur_log->log_time);
+ break;
+
+ default:
+ arla_log(ADEBDISCONN,
+ "%d action is to do_replay: skipping the current op=%d",
+ count++,cur_log->log_op);
+ }
+ }
+
+ if (changed_fid ==0) {
+ clear_index_list(); /* clean all index when after discon */
+ clear_log_entry();
+ /* clean up, remove all associative data structures */
+ fid_AD_tail = fid_AD_head;
+ while(fid_AD_tail)
+ {
+ fid_tmp = fid_AD_tail->next;
+ free(fid_AD_tail);
+ fid_AD_tail = fid_tmp;
+ }
+ /* SWW Qiyue 28: We need to reset head to 0*/
+ fid_AD_head = 0;
+ fid_KP_tail = fid_KP_head;
+ while(fid_KP_tail)
+ {
+ fid_keep *fid_tmp;
+
+ fid_tmp = fid_KP_tail->next;
+ free(fid_KP_tail);
+ fid_KP_tail = fid_tmp;
+ }
+
+ fid_KP_head = 0;
+ }
+ terminate:
+
+ arla_warnx (ADEBDISCONN,"We have done total %d replays",count-1);
+ close(fd);
+ free(cur_log);
+ return;
+}
+
+/*
+ *
+ */
+
+static int
+check_rm_fid (VenusFid v1, VenusFid v2)
+{
+ if(v1.fid.Vnode == v2.fid.Vnode &&
+ v1.fid.Volume == v2.fid.Volume &&
+ v1.fid.Unique == v2.fid.Unique )
+ return 1;
+ else
+ return 0;
+}
+
+/*
+ *
+ */
+
+static int
+check_log_fid(struct vcache vc, VenusFid *fid)
+{
+ log_ent_t *temp = log_head.next;
+
+ if (vc.fid.fid.Vnode == fid->fid.Vnode &&
+ vc.fid.fid.Volume == fid->fid.Volume &&
+ vc.fid.fid.Unique == fid->fid.Unique)
+ return 1;
+
+ while (temp!=0) {
+ switch(temp->log_op) {
+ case DIS_RENAME:
+ if (check_rm_fid(temp->rn_oparentfid,*fid)==1)
+ return 1;
+ default:
+ temp = temp->next;
+ break;
+ }
+ }
+ return 0;
+}
+
+/*
+ *
+ */
+
+static int
+check_log_todo(log_ent_t * cur_log , VenusFid *fid, VenusFid *newfid)
+{
+ VenusFid *lookfid;
+ struct vcache vc, vc_new;
+ int will_do = 0;
+
+ if (newfid->fid.Vnode ==0 &&
+ newfid->fid.Volume == 0 &&
+ newfid->fid.Unique ==0)
+ lookfid = fid;
+ else
+ lookfid = newfid; /* For create and putdata */
+
+ switch (cur_log->log_op){
+ case DIS_STORE:
+ vc.fid = cur_log->st_fid;
+ will_do = check_log_fid(vc, lookfid);
+ if (will_do==1) {
+ set_fid_value(newfid, 0);
+ return 1;
+ }
+ break;
+ case DIS_SETATTR:
+ vc.fid = cur_log->sa_fid;
+ will_do = check_log_fid(vc, lookfid);
+ if (will_do==1) {
+ set_fid_value(newfid , &cur_log->sa_fid);
+ return 1;
+ }
+ break;
+ case DIS_REMOVE:
+ vc.fid = cur_log->rm_filefid;
+ will_do = check_log_fid(vc, lookfid);
+ if (will_do==1) {
+ return 1;
+ }
+ break;
+ case DIS_RMDIR:
+ vc.fid = cur_log->rd_parentfid;
+ will_do = check_log_fid(vc, lookfid);
+ if (will_do==1) {
+ return 1;
+ }
+ break;
+ case DIS_RENAME:
+ vc.fid = cur_log->rn_oparentfid;
+ will_do = check_log_fid(vc, lookfid);
+ if (will_do==1) {
+ return 1;
+ }
+ vc_new.fid = cur_log->rn_nparentfid;
+ will_do = check_log_fid(vc_new, lookfid);
+ if (will_do==1) {
+ return 1;
+ }
+ break;
+ case DIS_MKDIR:
+ vc.fid = cur_log->md_parentfid;
+ will_do = check_log_fid(vc, lookfid);
+ if (will_do==1) {
+ return 1;
+ }
+ break;
+ case DIS_LINK:
+ break;
+ case DIS_SYMLINK:
+ will_do = check_log_fid(vc, lookfid);
+ if (will_do==1) {
+ return 1;
+ }
+ break;
+ case DIS_CREATE:
+ vc.fid = cur_log->cr_parentfid;
+ will_do = check_log_fid(vc, lookfid);
+ if (will_do==1) {
+ set_fid_value(newfid , &cur_log->cr_filefid);
+ return 1;
+ }
+ break;
+ case DIS_FSYNC:
+ case DIS_ACCESS:
+ case DIS_READDIR:
+ case DIS_READLINK:
+ case DIS_INFO:
+ case DIS_START_OPT:
+ case DIS_END_OPT:
+ case DIS_REPLAYED:
+ /* A no op */
+ break;
+ }
+ return 0;
+}
+
+
+#if 0
+
+/*
+ *
+ */
+
+void
+keepfid_newrename(char *name,
+ AFSFid fid)
+{
+ if (fid_KP_head == 0) {
+ fid_KP_head = (fid_keep *)malloc(sizeof(fid_keep));
+ assert(fid_KP_head);
+
+ strcpy(fid_KP_head->name, name);
+ fid_KP_head->kept_fid = fid;
+ fid_KP_head->next = 0;
+ }
+ else {
+ fid_keep *temp;
+
+ temp = (fid_keep *)malloc(sizeof(fid_keep));
+ assert(temp);
+
+ strcpy(temp->name, name);
+ temp->name[strlen(name)] = '\0';
+ temp->kept_fid = fid;
+ temp->next = fid_KP_head->next;
+ fid_KP_head->next = temp;
+ }
+}
+
+#endif
+
+/*
+ *
+ */
+
+static int
+find_venus (char *name, VenusFid *fid)
+{
+ fid_keep *fid_temp;
+
+ if(fid_KP_head == 0 )
+ return 1; /*error */
+
+ fid_temp = fid_KP_head;
+
+ while(fid_temp) {
+ if (strcmp(fid_temp->name,name) == 0) {
+ fid->fid.Volume = fid_temp->kept_fid.Volume;
+ fid->fid.Vnode = fid_temp->kept_fid.Vnode;
+ fid->fid.Unique = fid_temp->kept_fid.Unique;
+ return 0;
+ }
+ fid_temp = fid_temp->next;
+ }
+ arla_warnx (ADEBDISCONN, "find_venus: *PANIC* not found fid for %s", name);
+ return 1;
+}
+
+
+/*
+ *
+ */
+
+static VenusFid *
+fid_translate(VenusFid *fid_in)
+{
+ fid_trans *fid_tmp;
+ VenusFid *fid_ret;
+
+ if (!fid_AD_head)
+ return fid_in;
+
+ fid_tmp = fid_AD_head;
+
+ while(fid_tmp){
+
+ fid_ret=&fid_tmp->logged_fid;
+
+ if ((fid_ret->Cell == fid_in->Cell) &&
+ (fid_ret->fid.Volume == fid_in->fid.Volume) &&
+ (fid_ret->fid.Vnode == fid_in->fid.Vnode) &&
+ (fid_ret->fid.Unique == fid_in->fid.Unique))
+ return &fid_tmp->fetched_fid;
+
+ fid_tmp = fid_tmp->next;
+ }
+ return fid_in;
+}
+
+/*
+ *
+ */
+
+static void
+clear_index_list(void)
+{
+ index_list *temp=index_head;
+
+ while(temp!=0) {
+ index_list *tmp;
+
+ tmp = temp->next;
+ free(temp);
+ temp = tmp;
+ }
+ index_head = 0;
+}
+
+/*
+ *
+ */
+
+static void
+clear_log_entry(void)
+{
+ log_ent_t *temp=log_head.next;
+
+ while(temp!=0) {
+ log_ent_t *tmp;
+
+ tmp = temp->next;
+ free(temp);
+ temp = tmp;
+ }
+ log_head.next = 0;
+}
+
+/*
+ *
+ */
+
+static int
+is_done_before(int no)
+{
+ index_list * temp = index_head;
+
+ while(temp !=0) {
+ if (temp->index == no)
+ return 1;
+ else
+ temp = temp->next;
+ }
+ return 0;
+}
+
+/*
+ *
+ */
+
+static void
+add_done_list(int no)
+{
+ if (!index_head) {
+ index_head = (index_list *)malloc(sizeof(index_list));
+ assert(index_head);
+ index_head->index = no;
+ index_head->next = 0;
+ } else {
+ index_list * temp;
+ temp = (index_list *) malloc(sizeof(index_list));
+ assert(temp);
+ temp->next = index_head->next;
+ index_head->next = temp;
+ temp->index = no;
+ }
+}
+
+/*
+ *
+ */
+
+static void
+alloc_fid_trans(VenusFid *logged_fid)
+{
+ if (!fid_AD_head)
+ {
+ /*SWW Qiyue 28 Make sure we have the memory*/
+ fid_AD_head = (fid_trans *) malloc(sizeof(fid_trans));
+ assert(fid_AD_head);
+
+ fid_AD_head->prev=fid_AD_head->next = 0;
+ fid_AD_tail = fid_AD_head;
+ fid_AD_tail->logged_fid = *logged_fid;
+
+ } else{
+
+ /*SWW Qiyue 28 Make sure we have the memory*/
+ fid_AD_tail->next = (fid_trans *) malloc(sizeof(fid_trans));
+ assert(fid_AD_tail->next);
+
+ fid_AD_tail->next->prev = fid_AD_tail;
+ fid_AD_tail->next->next = 0;
+ fid_AD_tail = fid_AD_tail->next; /*Ba ba: move tail ahead */
+ fid_AD_tail->logged_fid = *logged_fid;
+ }
+}
+
+/*
+ *
+ */
+
+static void
+fill_fid_trans (VenusFid *fetched_fid)
+{
+ fid_AD_tail->fetched_fid = *fetched_fid;
+}
+
+/*
+ *
+ */
+
+#if 0
+void
+update_entry_flag (FCacheEntry *entry)
+{
+ entry->flags.attrp = FALSE;
+ entry->flags.datap = FALSE;
+}
+#endif
+
+/*
+ *
+ */
+
+int reconnect_nonmute(struct vcache *vcp, int op, struct timeval log_time)
+{
+ FCacheEntry *fce, fce_fetched;
+ CredCacheEntry *ce;
+ int error;
+ VenusFid *fid;
+#if 0
+ ConnCacheEntry *conn;
+#endif
+
+ arla_warnx (ADEBDISCONN,
+ "Start of reconnect_nonmute by sww"); /*SWW Qiyue 25*/
+
+ fid = &(vcp->fid);
+ if (fid->Cell == -1) /* newly created file, skip reconnect */
+ return 0;
+
+ error = fcache_find(&fce, *fid);
+ /* assert(fce); */
+ if (error) /* nonmute op on nonexisting data */
+ {
+ arla_log(ADEBDISCONN,
+ "reconnect: nonmute op %d performed on cache "
+ "entry no longer exist locally!",
+ op);
+ return -1;
+ }
+
+ arla_log(ADEBDISCONN,
+ "reconnect: DISCONNECTED nonmute "
+ "on fid.Cell=0x%x, fid.fid.Volume= 0x%x, fid.fid.Vnode=0x%x, "
+ "fid.fid.Unique=0x%x", fid->Cell,
+ fid->fid.Volume,
+ fid->fid.Vnode,
+ fid->fid.Unique);
+
+ ce = cred_get (fid->Cell, vcp->cred.pag, CRED_ANY);
+ assert (ce != NULL);
+ error = 0;
+
+ /* setting some stuff so do_read_attr would work */
+ fce->flags.attrp = TRUE;
+ fce->callback.CallBackType = 2;
+ fce_fetched = *fce;
+ /*conn = findconn (fce, ce);*/
+
+ error = read_attr(&fce_fetched, ce);
+
+ arla_log(ADEBDISCONN,
+ "reconnect: logged DataVersion=%d, "
+ "fetched DataVersion=%d",
+ vcp->DataVersion,
+ fce_fetched.status.DataVersion);
+
+ if (vcp->DataVersion < fce_fetched.status.DataVersion)
+ {
+ if (log_time.tv_usec >= fce_fetched.status.ServerModTime)
+ arla_log(ADEBDISCONN,
+ "Warning: nonmutating operation %d read stale data!",
+ op);
+ else if (log_time.tv_usec <= fce_fetched.status.ServerModTime &&
+ (vcp->DataVersion +1) == fce_fetched.status.DataVersion)
+ arla_log(ADEBDISCONN,
+ "Notice: file modified once after nonmutating "
+ "operation %d.",
+ op);
+ else
+ arla_log(ADEBDISCONN,
+ "Warning: nonmutating operation %d might have read "
+ "stale data!", op);
+ }
+
+ ReleaseWriteLock(&fce->lock);
+ cred_free(ce);
+ /*conn_free(conn);*/
+
+ return error;
+}
+
+/*
+ *
+ */
+
+int reconnect_remove(struct vcache *vcp, FCacheEntry *childentry, char *name)
+{
+ FCacheEntry *fce;
+ CredCacheEntry *ce;
+ int error;
+ VenusFid *fid, tempfid; /* Ba san: to check the deletion of file*/
+ Result res;
+ int isupdate;
+
+ ConnCacheEntry *conn;
+ fs_server_context context;
+ AFSFetchStatus status;
+ AFSVolSync volsync;
+ char tmp[5];
+ xfs_cache_handle cache_handle;
+
+ fid = &(vcp->fid); /* points to the VenusFid structure */
+ fid = fid_translate(fid);
+
+ arla_log(ADEBDISCONN, "reconnect: DISCONNECTED remove on "
+ "fid.Cell=0x%x, fid.fid. Volume= 0x%x, fid.fid.Vnode=0x%x, "
+ "fid.fid.Unique=0x%x",
+ fid->Cell, fid->fid.Volume, fid->fid.Vnode, fid->fid.Unique);
+
+ /* ObtainWriteLock called in fcache_find */
+ error = fcache_find(&fce, *fid);
+ assert (error == 0);
+
+ ce = cred_get (fid->Cell, vcp->cred.pag, CRED_ANY);
+ assert (ce != NULL);
+
+ if (connected_mode != CONNMODE_PARCONNECTED) {
+ ObtainWriteLock(&childentry->lock);
+ isupdate = reconnect_mut_chk(childentry, ce,
+ childentry->status.DataVersion);
+ ReleaseWriteLock(&childentry->lock);
+
+ if (isupdate)
+ {
+ xfs_cache_handle cache_handle;
+
+ arla_log(ADEBDISCONN,
+ "reconnect_remove: can't remove because file modified!");
+ cred_free(ce);
+ adir_creat (fce, name, childentry->fid.fid);
+ childentry->flags.attrp = FALSE;
+ ReleaseWriteLock(&fce->lock);
+ conv_dir (fce, ce, 0, &cache_handle, tmp, sizeof(tmp));
+ ReleaseWriteLock(&fce->lock);
+ return -1;
+ }
+ } /* Ba ershi: we dont need to do it in parconn */
+
+ res.res = 0;
+
+ assert (CheckLock(&fce->lock) == -1);
+
+ conn = find_first_fs (fce, ce, &context);
+
+/* Ba san: check the file exists
+
+ ReleaseWriteLock(&fce->lock);
+ error = adir_lookup(fce->fid, name, &tempfid, ce);
+ assert (error == 0);
+ ObtainWriteLock(&fce->lock); */
+
+ res.res = RXAFS_RemoveFile (conn->connection,
+ &fce->fid.fid,
+ name,
+ &status,
+ &volsync);
+ if (res.res) {
+ arla_log (ADEBDISCONN, "Could not RemoveFile: %s (%d)",
+ koerr_gettext(res.res), res.res);
+ goto out;
+ }
+
+ arla_warnx (ADEBDISCONN,"In reconnect_remove: Remove the file %s",name);
+
+/* Ba san: Chcek the deletion of the file */
+ ReleaseWriteLock(&fce->lock);
+ error = adir_lookup(fce->fid, name, &tempfid, ce);
+ ObtainWriteLock(&fce->lock);
+
+ if (error == 0) {
+ int result;
+
+ arla_warnx (ADEBDISCONN,
+ "In reconnect_remove: file %s needs to be deleted",
+ name);
+ result = adir_remove (fce,name);
+ assert ( result == 0);
+ } /* This is for the file produced during disconnect mode,
+ if error==ENOENT then the file is created during connect mode*/
+
+
+ fce->status = status;
+ fce->volsync = volsync;
+ childentry->host = 0; /* Ba shiliu dont get callback */
+
+ volcache_update_volsync (fce->volume, fce->volsync);
+ conv_dir (fce, ce, 0, &cache_handle, tmp, sizeof(tmp));
+
+ out:
+
+ cred_free(ce);
+ free_fs_server_context(&context);
+ ReleaseWriteLock(&fce->lock);
+ return error;
+}
+
+/*
+ *
+ */
+
+int
+reconnect_rmdir(struct vcache *vcp, FCacheEntry *childEntry, char *name)
+{
+ FCacheEntry *fce;
+ CredCacheEntry *ce;
+ int error;
+ VenusFid *fid, tempfid; /* Ba san: to check the deletion of file*/
+ Result res;
+ char tmp[5];
+ int ret = 0;
+ Result tempres;
+ xfs_cache_handle cache_handle;
+
+ ConnCacheEntry *conn;
+ fs_server_context context;
+ AFSFetchStatus status;
+ AFSVolSync volsync;
+
+ fid = &(vcp->fid); /* points to the VenusFid structure */
+ fid = fid_translate(fid);
+
+ ret = fcache_find(&fce, *fid);
+ assert (ret == 0);
+
+ ce = cred_get (fid->Cell, vcp->cred.pag, CRED_ANY);
+ assert (ce != NULL);
+
+ assert (CheckLock(&fce->lock) == -1);
+
+ conn = find_first_fs (fce, ce, &context);
+
+ ret = RXAFS_RemoveDir (conn->connection,
+ &fce->fid.fid,
+ name,
+ &status,
+ &volsync);
+ if (ret) {
+ arla_log (ADEBDISCONN,
+ "Could not RemoveDir : %s (%d)",
+ koerr_gettext(res.res),res.res);
+ goto out;
+ }
+
+/* Ba san: Chcek the deletion of the file */
+ ReleaseWriteLock(&fce->lock);
+ error = adir_lookup(fce->fid, name, &tempfid, ce);
+ ObtainWriteLock(&fce->lock);
+
+ if (error == 0) {
+ int result;
+
+ arla_warnx (ADEBDISCONN,
+ "In reconnect_rmdir: file %s needs to be deleted",name);
+ result = adir_remove (fce,name);
+ assert ( result == 0);
+ } /* This is for the file produced during disconnect mode,
+ if error==ENOENT then the file is created during connect mode*/
+
+ fce->status = status;
+ fce->volsync = volsync;
+
+ volcache_update_volsync (fce->volume, fce->volsync);
+
+ tempres = conv_dir(fce, ce, 0, &cache_handle, tmp, sizeof(tmp));
+
+ childEntry->host = 0; /*Ba shiqi: no callback for this entry*/
+
+ out:
+
+ cred_free(ce);
+ free_fs_server_context(&context);
+ ReleaseWriteLock(&fce->lock);
+ return error;
+}
+
+/*
+ *
+ */
+
+static int
+reconnect_mut_chk(FCacheEntry *fce, CredCacheEntry *ce, int version)
+{
+ ConnCacheEntry *conn;
+ fs_server_context context;
+ FCacheEntry fetched = *fce;
+ int ret;
+
+ AFSFetchStatus status;
+ AFSCallBack callback;
+ AFSVolSync volsync;
+
+ assert (CheckLock (&fetched.lock) == -1);
+
+/*SWW Aug 01: >= is changed into > */
+ conn = find_first_fs (&fetched, ce, &context);
+
+ ret = RXAFS_FetchStatus (conn->connection,
+ &fce->fid.fid,
+ &status,
+ &callback,
+ &volsync);
+ if (ret) {
+ if (ret == -1)
+ ret = ENETDOWN;
+ free_fs_server_context(&context);
+ arla_warn (ADEBFCACHE, ret, "fetch-status");
+ return ret;
+ }
+
+ if (status.DataVersion > version)
+ {
+ arla_log(ADEBDISCONN, "reconnect_mut_chk: concurrent writes detected!");
+ return 1;
+ }
+ free_fs_server_context(&context);
+ return 0;
+}
+
+/*
+ *
+ */
+
+void fcache_backfile_name(char *name, size_t len)
+{
+ static int no = 1;
+
+ snprintf (name, len, "%04X",no++);
+ strcat (name, "bak");
+ name[strlen(name)+1] = '\0';
+}
+
+/*
+ *
+ */
+
+void
+copy_cached_file(int from, int to)
+{
+ char tmpname[5],name_from[21],name_to[27];
+ int fd_from, n, fd_to;
+ char buf[BUFSIZE];
+
+ strcpy(name_from,ARLACACHEDIR);
+ strcpy(name_to,ARLACACHEDIR);
+ sprintf(tmpname,"%04X",from);
+ strcat(name_from, tmpname);
+ sprintf(tmpname,"%04X",to);
+ strcat(name_to, tmpname);
+ fd_from = open(name_from,O_RDONLY | O_BINARY);
+ fd_to = open(name_to, O_WRONLY | O_CREAT | O_BINARY);
+
+ while((n = read(fd_from, buf, BUFSIZE)) > 0)
+ write(fd_to, buf, n);
+
+#if 0
+ if(fstat(fd_to, &statinfo)<0) {
+ arla_warnx(ADEBDISCONN,"ERROR");
+ }
+#endif
+
+ close(fd_from);
+ close(fd_to);
+}
+
+/*
+ *
+ */
+
+int
+reconnect_mut_newfile(FCacheEntry **fcep, pag_t cred,VenusFid *new_fid)
+{
+
+ FCacheEntry *parent_fce;
+ u_long host;
+ char name[9],tmp[5];
+ AFSStoreStatus store_attr;
+ AFSFetchStatus fetch_attr;
+ CredCacheEntry *ce;
+ AccessEntry *ae;
+ VenusFid newfid;
+ int ret;
+ int from, to;
+ xfs_cache_handle cache_handle;
+
+ ret = fcache_find (&parent_fce, (*fcep)->parent);
+ assert (ret == 0);
+
+ host = (*fcep)->host;
+
+ ce = cred_get((*fcep)->parent.Cell, cred, CRED_ANY);
+
+ fcache_backfile_name (name, sizeof(name));
+
+ store_attr.Mask = 8;
+ store_attr.ClientModTime = 430144;
+ store_attr.Owner = 1957724;
+ store_attr.Group = 21516;
+ store_attr.UnixModeBits = 420;
+ store_attr.SegSize = 0;
+
+ create_file(parent_fce, name, &store_attr, &newfid, &fetch_attr, ce);
+
+ (*fcep)->flags.datap = FALSE; /* Ba shiqi: we need to get the old from FS*/
+ *new_fid = newfid;
+ from = (*fcep)->index;
+ ret = fcache_find(fcep, newfid);
+ assert (ret == 0);
+ to = (*fcep)->index;
+ (*fcep)->host = host;
+ (*fcep)->flags.attrp = TRUE;
+ (*fcep)->flags.datap = TRUE;
+ findaccess(ce->cred, (*fcep)->acccache, &ae); /*Ba shijiu obtain access */
+ ae->cred = ce->cred;
+ ae->access = (*fcep)->status.CallerAccess;
+
+ ReleaseWriteLock(&(*fcep)->lock);
+
+ copy_cached_file(from, to);
+ ret = adir_creat (parent_fce, name, newfid.fid);
+ assert (ret ==0);
+ conv_dir (parent_fce, ce, 0, &cache_handle, tmp, sizeof(tmp));
+ ReleaseWriteLock(&parent_fce->lock);
+
+ return 0;
+}
+
+
+/*
+ *
+ */
+
+int reconnect_putattr(struct vcache *vcp, struct xfs_attr *xap)
+{
+
+ ConnCacheEntry *conn;
+ fs_server_context context;
+ struct rx_call *call;
+ VenusFid *fid;
+ CredCacheEntry *ce;
+ FCacheEntry *fce, *tempce;
+ AFSFetchStatus status;
+ Result res;
+ u_int32_t sizefs;
+ AFSStoreStatus storestatus;
+ AFSCallBack callback;
+ AFSVolSync volsync;
+ int ret;
+
+ fid = &(vcp->fid); /* points to the VenusFid structure */
+ fid = fid_translate(fid);
+
+#if 0
+ arla_log(ADEBDISCONN, "reconnect: DISCONNECTED write on fid.Cell=0x%x, "
+ "fid.fid.Volume= 0x%x, fid.fid.Vnode=0x%x, fid.fid.Unique=0x%x",
+ fid->Cell,
+ fid->fid.Volume,
+ fid->fid.Vnode,
+ fid->fid.Unique);
+#endif
+
+ ce = cred_get (fid->Cell, vcp->cred.pag, CRED_ANY);
+ assert (ce != NULL);
+ res.res = 0;
+
+#if 0
+/* Ba shier: should we send the file back to server? */
+ if (XA_VALID_SIZE(xap)){
+ res = cm_ftruncate (*fid, xap->xa_size, ce);
+ }
+#endif
+
+ ret = fcache_find(&fce, *fid);
+ assert (ret == 0);
+ tempce = fce;
+
+ sizefs=fce->status.Length;
+
+ /* some people have written to the file while we are disconnected */
+ /* we have to give it a different name on the server */
+ if (reconnect_mut_chk(fce, ce, vcp->DataVersion))
+ {
+ VenusFid new_fid;
+
+ alloc_fid_trans(fid);
+ reconnect_mut_newfile(&fce,vcp->cred.pag,&new_fid);
+ fce->status.Length = sizefs;
+ ReleaseWriteLock(&tempce->lock);
+ fill_fid_trans(&new_fid);
+ tempce->flags.attrp = FALSE;
+ tempce->flags.kernelp = FALSE;
+ }
+
+#if 0
+ usedbytes -= entry->status.Length;
+ usedbytes += size;
+
+ fce->status.Length = size;
+#endif
+
+ /* code from truncate file XXX join */
+ conn = find_first_fs (fce, ce, &context);
+
+ call = rx_NewCall (conn->connection);
+ if (call == NULL) {
+ arla_log (ADEBDISCONN, "Cannot call");
+ res.res = ENOMEM;
+ goto out;
+ }
+
+ storestatus.Mask = 0;
+ res.res = StartRXAFS_StoreData (call,
+ &(fce->fid.fid),
+ &storestatus,
+ 0, 0, fce->status.Length);
+ if(res.res) {
+ arla_log (ADEBDISCONN, "Could not start store, %s (%d)",
+ koerr_gettext(res.res), res.res);
+ rx_EndCall(call, 0);
+ goto out;
+ }
+
+ sizefs = htonl (sizefs);
+ if (rx_Write (call, &sizefs, sizeof(sizefs)) != sizeof(sizefs)) {
+ res.res = rx_Error(call);
+ arla_log (ADEBDISCONN, "Error writing length: %d", res.res);
+ rx_EndCall(call, 0);
+ goto out;
+ }
+
+ if (rx_Write (call, 0, 0) != 0) {
+ res.res = rx_Error(call);
+ arla_log (ADEBDISCONN, "Error writing: %d", res.res);
+ rx_EndCall(call, 0);
+ goto out;
+ }
+
+ res.res = rx_EndCall (call, EndRXAFS_StoreData (call,
+ &status,
+ &callback,
+ &volsync));
+ if (res.res) {
+ arla_log (ADEBDISCONN, "Error rx_EndCall: %s (%d)",
+ koerr_gettext(res.res), res.res);
+ goto out;
+ }
+
+ fce->status = status;
+ fce->callback = callback;
+ fce->volsync = volsync;
+
+ volcache_update_volsync (fce->volume, fce->volsync);
+
+ /* code from write_attr XXX join */
+ xfs_attr2afsstorestatus(xap, &storestatus);
+
+ res.res = RXAFS_StoreStatus (conn->connection,
+ &fce->fid.fid,
+ &storestatus,
+ &status,
+ &volsync);
+ if (res.res) {
+ arla_log (ADEBDISCONN, "Could not make store-status call, %s (%d)",
+ koerr_gettext(res.res), res.res);
+ goto out;
+ }
+ arla_log(ADEBDISCONN,
+ "write_attr: status.Length = %d", status.Length);
+ fce->status = status;
+ fce->volsync = volsync;
+
+ volcache_update_volsync (fce->volume, fce->volsync);
+
+ out:
+
+ free_fs_server_context(&context);
+ ReleaseWriteLock(&fce->lock);
+ cred_free(ce);
+ return res.res;
+}
+
+/*
+ *
+ */
+
+static int
+reconnect_putdata(struct vcache *vcp)
+{
+ VenusFid *fid;
+ FCacheEntry *fce;
+ CredCacheEntry *ce;
+ Result res;
+
+ u_int32_t sizefs;
+ int fd = -1;
+ struct rx_call *call;
+ ConnCacheEntry *conn;
+ fs_server_context context;
+ struct stat statinfo;
+ AFSStoreStatus storestatus;
+ AFSFetchStatus status;
+ AFSCallBack callback;
+ AFSVolSync volsync;
+ int ret;
+
+ fid = &(vcp->fid); /* points to the VenusFid structure */
+ arla_log(ADEBDISCONN, "reconnect: putdata before fid_translate, "
+ "fid->Cell=0x%x, fid->fid.Volume=0x%x, fid->fid.Vnode=0x%x, "
+ "fid->fid.Unique=0x%x",
+ fid->Cell,
+ fid->fid.Volume,
+ fid->fid.Vnode,
+ fid->fid.Unique);
+
+ fid = fid_translate(fid);
+
+ arla_log(ADEBDISCONN, "reconnect: putdata after fid_translate, "
+ "fid->Cell=0x%x, fid->fid.Volume=0x%x, fid->fid.Vnode=0x%x, "
+ "fid->fid.Unique=0x%x",
+ fid->Cell,
+ fid->fid.Volume,
+ fid->fid.Vnode,
+ fid->fid.Unique);
+
+
+ ce = cred_get (fid->Cell, vcp->cred.pag, CRED_ANY);
+ assert (ce != NULL);
+
+ ret = fcache_find (&fce, *fid);
+ assert (ret == 0);
+
+#if 0
+ isupdate = reconnect_mut_chk(fce, ce, vcp->DataVersion);
+ if (isupdate)
+ {
+ arla_log(ADEBDISCONN,
+ "reconnect_putdata: send data back because "
+ "the file was modified!");
+ cred_free(ce);
+ ReleaseWriteLock(&fce->lock);
+ reconnect_mut_newfile(&fce, vcp->cred.pag);
+ return -1;
+ }
+
+ if (reconnect_mut_chk (fce, ce)) {
+ arla_log (ADEBDISCONN, "Reconnect_putdata: can not send the file"
+ "to FS becausethis file has been modified!");
+ ReleaseWriteLock(&fce->lock);
+ return -1;
+ }
+#endif
+
+ /* code taken from write_data XXX join */
+ assert (CheckLock(&fce->lock) == -1);
+
+ conn = find_first_fs (fce, ce, &context);
+
+ fd = fcache_open_file (fce, O_RDONLY);
+ if (fd < 0) {
+ arla_log (ADEBDISCONN, "open %u failed", fce->index);
+ res.res = errno;
+ goto out;
+ }
+
+ if (fstat (fd, &statinfo) < 0) {
+ arla_log (ADEBDISCONN, "Cannot stat file %u", fce->index);
+ res.res = errno;
+ goto out;
+ }
+
+ sizefs = statinfo.st_size;
+
+ call = rx_NewCall (conn->connection);
+ if (call == NULL) {
+ arla_log (ADEBDISCONN, "Cannot call");
+ res.res = ENOMEM;
+ goto out;
+ }
+
+ storestatus.Mask = 0; /* Dont save anything */
+ res.res = StartRXAFS_StoreData (call, &fce->fid.fid,
+ &storestatus,
+ 0,
+ sizefs,
+ sizefs);
+ if (res.res) {
+ arla_log (ADEBDISCONN, "Could not start store, %s (%d)",
+ koerr_gettext(res.res), res.res);
+ rx_EndCall(call, 0);
+ goto out;
+ }
+
+ res.res = copyfd2rx (fd, call, sizefs);
+ if (res.res) {
+ rx_EndCall(call, res.res);
+ arla_log (ADEBDISCONN, "copyfd2rx failed: %d", res.res);
+ goto out;
+ }
+
+ res.res = rx_EndCall (call, EndRXAFS_StoreData (call,
+ &status,
+ &callback,
+ &volsync));
+ if (res.res) {
+ arla_log (ADEBDISCONN, "Error rx_EndCall: %s (%d)",
+ koerr_gettext(res.res), res.res);
+ goto out;
+ }
+ if (status.DataVersion > fce->status.DataVersion)
+ arla_log(ADEBDISCONN,
+ "reconnect: putdata, server incremented DataVersion!");
+
+ fce->status = status;
+ fce->callback = callback;
+ fce->volsync = volsync;
+
+ volcache_update_volsync (fce->volume, fce->volsync);
+
+ out:
+
+ ReleaseWriteLock(&fce->lock);
+ if (fd != -1)
+ close (fd);
+ free_fs_server_context (&context);
+
+ cred_free(ce);
+ return res.res;
+}
+
+/*
+ *
+ */
+
+int reconnect_rename(struct vcache *vcp_old, struct vcache *vcp_new,
+ char *name_old, char *name_new)
+{
+
+ FCacheEntry *fce_old, *fce_new;
+ CredCacheEntry *ce;
+ VenusFid *fid_old, *fid_new,foo_fid,*tempnew_fid;
+ int error;
+
+ int ret = 0;
+ Result res;
+ char tmp[5];
+ int isnewpar = 0;
+ ConnCacheEntry *conn;
+ fs_server_context context;
+ AFSFetchStatus orig_status, new_status;
+ AFSVolSync volsync;
+ xfs_cache_handle cache_handle;
+
+ fid_old = &vcp_old->fid;
+ fid_old = fid_translate(fid_old);
+
+ ret = fcache_find (&fce_old, *fid_old);
+ assert (ret == 0);
+
+ /* ReleaseWriteLock(&fce_old->lock); SWW Qiyue 28 Maybe we dont need it*/
+ assert(fce_old);
+ arla_log(ADEBDISCONN, "reconnect: old rename on Cell=0x%x, "
+ "fid.Volume= 0x%x, fid.Vnode=0x%x, fid.Unique=0x%x",
+ fce_old->fid.Cell,
+ fce_old->fid.fid.Volume,
+ fce_old->fid.fid.Vnode,
+ fce_old->fid.fid.Unique);
+
+ fid_new = tempnew_fid = &vcp_new->fid;
+ fid_new = fid_translate(fid_new);
+
+ if (tempnew_fid->fid.Volume != fid_new->fid.Volume ||
+ tempnew_fid->fid.Vnode != fid_new->fid.Vnode ||
+ tempnew_fid->fid.Unique != fid_new->fid.Unique)
+ isnewpar = 1;
+
+/*Ba ba: the parent dir was created during disconnected */
+
+ if (fid_old->fid.Volume == fid_new->fid.Volume &&
+ fid_old->fid.Vnode == fid_new->fid.Vnode &&
+ fid_old->fid.Unique == fid_new->fid.Unique )
+ ReleaseWriteLock(&fce_old->lock); /* old and new are the same*/
+
+ ret = fcache_find (&fce_new, *fid_new);
+ assert (ret == 0);
+
+ arla_log(ADEBDISCONN, "reconnect: new rename on Cell=0x%x, "
+ "fid.Volume= 0x%x, fid.Vnode=0x%x, fid.Unique=0x%x",
+ fce_new->fid.Cell,
+ fce_new->fid.fid.Volume,
+ fce_new->fid.fid.Vnode,
+ fce_new->fid.fid.Unique);
+
+
+
+ arla_log(ADEBDISCONN,
+ "reconnect_rename: fce_old = 0x%x, fce_new = 0x%x",
+ fce_old, fce_new);
+
+ ce = cred_get (vcp_old->fid.Cell, vcp_old->cred.pag, CRED_ANY);
+ assert (ce != NULL);
+
+ assert (CheckLock(&fce_old->lock) == -1
+ && CheckLock(&fce_new->lock) == -1);
+
+ conn = find_first_fs (fce_old, ce, &context);
+
+ error = RXAFS_Rename (conn->connection,
+ &fce_old->fid.fid,
+ name_old,
+ &fce_new->fid.fid,
+ name_new,
+ &orig_status,
+ &new_status,
+ &volsync);
+
+ if (error) {
+ arla_log (ADEBDISCONN, "Could not Rename: %s (%d)", koerr_gettext(error), error);
+ goto out; }
+
+ fce_old->status = orig_status;
+ fce_new->status = new_status;
+
+ fce_old->volsync = fce_new->volsync = volsync;
+
+ volcache_update_volsync (fce_old->volume, fce_old->volsync);
+
+
+/*SWW Aug 01 */
+ arla_warnx (ADEBDISCONN,
+ "reconnect_rename: we delete the old one %s volumn=0x%x, "
+ "vnode=0x%x,unique=0x%x",
+ name_old,fce_old->fid.fid.Volume,
+ fce_old->fid.fid.Vnode,
+ fce_old->fid.fid.Unique);
+
+/*Ba Yi: get the VenuseFid for new file */
+ #if 0
+ if (fid_old->fid.Volume == fid_new->fid.Volume &&
+ fid_old->fid.Vnode == fid_new->fid.Vnode &&
+ fid_old->fid.Unique == fid_new->fid.Unique ) ;
+#endif
+ ReleaseWriteLock(&fce_old->lock); /* old and new are the same*/
+
+ error = adir_lookup (fce_old->fid, name_old, &foo_fid, ce);
+
+#if 0
+ if (fid_old->fid.Volume == fid_new->fid.Volume &&
+ fid_old->fid.Vnode == fid_new->fid.Vnode &&
+ fid_old->fid.Unique == fid_new->fid.Unique );
+#endif
+ ObtainWriteLock (&fce_old->lock);
+
+/*Ba San: delete the old which was created during dis */
+ if (error == 0) {
+ arla_warnx (ADEBDISCONN,"reconnect_rename: we delete the old one %s "
+ "volumn=0x%x,vnode=0x%x,unique=0x%x",
+ name_old,
+ foo_fid.fid.Volume,
+ foo_fid.fid.Vnode,
+ foo_fid.fid.Unique);
+
+ adir_remove(fce_old,name_old);
+ adir_remove(fce_new,name_new);
+
+ res = conv_dir (fce_old, ce, 0, &cache_handle, tmp, sizeof(tmp));
+
+ } else {
+ /* if found delete it */
+/*Ba San: try to find the previous VenuseFid for old name */
+ if (error == ENOENT) {
+#if 0
+ if (fid_old->fid.Volume == fid_new->fid.Volume &&
+ fid_old->fid.Vnode == fid_new->fid.Vnode &&
+ fid_old->fid.Unique == fid_new->fid.Unique );
+#endif
+ ReleaseWriteLock(&fce_new->lock);
+
+ error = adir_lookup (fce_new->fid, name_new, &foo_fid, ce);
+
+#if 0
+ if (fid_old->fid.Volume == fid_new->fid.Volume &&
+ fid_old->fid.Vnode == fid_new->fid.Vnode &&
+ fid_old->fid.Unique == fid_new->fid.Unique );
+#endif
+ ObtainWriteLock (&fce_new->lock);
+ if (error == 0) /*Ba Si: We need delete the faked new */
+ adir_remove(fce_new,name_new);
+ else if (error == ENOENT) {
+ int venusret;
+
+ venusret = find_venus (name_new,&foo_fid);
+ assert (venusret==0);
+ arla_warnx (ADEBDISCONN,"I MUST WRITE A PROGRAM HERE");
+ if (isnewpar == 1) {
+
+ arla_warnx(ADEBDISCONN,"In reconnect_rename: "
+ "new Volume=0x%x,Vnode=0x%x,Unique=0x%x",
+ fce_new->fid.fid.Volume,
+ fce_new->fid.fid.Vnode,
+ fce_new->fid.fid.Unique);
+#if 0
+ error = adir_creat(fce_new, name_new, foo_fid.fid);
+#endif
+ }
+ }
+ }
+ }
+
+ arla_warnx (ADEBDISCONN,"reconnect_rename: we add the new one %s "
+ "volumn=0x%x,vnode=0x%x,unique=0x%x",
+ name_new,
+ foo_fid.fid.Volume,
+ foo_fid.fid.Vnode,
+ foo_fid.fid.Unique);
+ error = adir_creat (fce_new, name_new, foo_fid.fid);
+ res = conv_dir (fce_new, ce, 0, &cache_handle, tmp, sizeof(tmp));
+
+/* Aug 1 */
+
+ out:
+
+ free_fs_server_context (&context);
+
+ ReleaseWriteLock(&fce_new->lock);
+
+ if (fid_old->fid.Volume != fid_new->fid.Volume ||
+ fid_old->fid.Vnode != fid_new->fid.Vnode ||
+ fid_old->fid.Unique != fid_new->fid.Unique )
+ ReleaseWriteLock(&fce_old->lock); /* old and new are the same*/
+
+ cred_free(ce);
+ return error;
+}
+
+/* XXX */
+
+/*
+ *
+ */
+
+static void
+recon_hashtabdel (FCacheEntry *e)
+{
+}
+
+/*
+ *
+ */
+
+static void
+recon_hashtabadd (FCacheEntry *e)
+{
+}
+
+/*
+ *
+ */
+
+int reconnect_create(struct vcache *parent, struct vcache *child, char *name)
+{
+
+ ConnCacheEntry *conn;
+ fs_server_context context;
+ VenusFid *parent_fid;
+ VenusFid *child_fid;
+ VenusFid fakeFid;
+
+ CredCacheEntry *ce;
+ FCacheEntry *parentEntry;
+ FCacheEntry *childEntry;
+
+ AFSFetchStatus fetch_attr;
+ AFSStoreStatus store_attr;
+
+ Result res;
+ AFSFetchStatus status;
+ AFSCallBack callback;
+ AFSVolSync volsync;
+ int ret;
+ char tmp[5];
+ xfs_cache_handle cache_handle;
+ int32_t type;
+
+ parent_fid = &(parent->fid); /* points to the VenusFid structure */
+ child_fid = &(child->fid);
+ fakeFid = *child_fid;
+
+ /*Ba Liu: the parent dir may be created during dison mode*/
+ parent_fid = fid_translate(parent_fid);
+
+ ce = cred_get (parent->fid.Cell, parent->cred.pag, CRED_ANY);
+ assert (ce != NULL);
+
+ ret = fcache_find (&parentEntry, *parent_fid);
+ assert (ret == 0);
+
+#if 0
+ is_change = reconnect_mut_chk(parentEntry,
+ ce,
+ parentEntry->status.DataVersion);
+#endif
+
+/*SWW Qiyue 30 delete the old file entry in dir */
+ arla_warnx (ADEBDISCONN,
+ "reconnect_rename: we delete the old one volumn=0x%x, "
+ "vnode=0x%x,unique=0x%x",
+ parentEntry->fid.fid.Volume,
+ parentEntry->fid.fid.Vnode,
+ parentEntry->fid.fid.Unique);
+
+ adir_remove(parentEntry,name);
+
+ conn = find_first_fs (parentEntry, ce, &context);
+
+ if (conn == NULL) {
+ arla_log (ADEBDISCONN, "Cannot call");
+ res.res = ENOMEM;
+ goto out;
+ }
+
+ ret = fcache_find (&childEntry, *child_fid);
+ assert (ret == 0);
+
+ recon_hashtabdel(childEntry);
+
+#if 0
+ fetch_attr = &childEntry->status;
+#endif
+
+ store_attr.Mask = 8;
+ store_attr.ClientModTime = childEntry->status.ClientModTime;
+ store_attr.Owner = childEntry->status.Owner;
+ store_attr.Group = childEntry->status.Group;
+ store_attr.UnixModeBits = childEntry->status.UnixModeBits;
+ store_attr.SegSize = childEntry->status.SegSize;
+
+ arla_log(ADEBDISCONN,
+ "reconnect: create before RXAFS_CreateFile, "
+ "Cell=0x%x, fid.Volume= 0x%x, fid.Vnode=0x%x, fid.Unique=0x%x",
+ childEntry->fid.Cell,
+ childEntry->fid.fid.Volume,
+ childEntry->fid.fid.Vnode,
+ childEntry->fid.fid.Unique);
+
+ alloc_fid_trans(&childEntry->fid);
+
+
+ ret = RXAFS_CreateFile (conn->connection,
+ &(parentEntry->fid.fid),
+ name, &store_attr,
+ &(childEntry->fid.fid), &fetch_attr,
+ &status,
+ &callback,
+ &volsync);
+
+ if (ret) {
+ if (ret == 17) {
+ ReleaseWriteLock(&parentEntry->lock);
+ reconnect_mut_newfile(&childEntry,
+ parent->cred.pag,
+ &childEntry->fid);
+ ObtainWriteLock(&parentEntry->lock);
+ fill_fid_trans(&childEntry->fid);
+ recon_hashtabadd(childEntry);
+ childEntry->host = rx_HostOf (rx_PeerOf (conn->connection));
+ update_kernelfid(fakeFid, childEntry->fid);
+ } else {
+ arla_log (ADEBDISCONN, "Could not CreateFile: %s (%d)",
+ koerr_gettext(ret), ret);
+ }
+ goto out;
+ }
+
+ parentEntry->status = status;
+ parentEntry->callback = callback;
+ parentEntry->volsync = volsync;
+
+ childEntry->fid.Cell = parentEntry->fid.Cell;
+
+ arla_log(ADEBDISCONN, "reconnect: create after RXAFS_CreateFile, "
+ "Cell=0x%x, fid.Volume= 0x%x, fid .Vnode=0x%x, fid.Unique=0x%x",
+ childEntry->fid.Cell,
+ childEntry->fid.fid.Volume,
+ childEntry->fid.fid.Vnode,
+ childEntry->fid.fid.Unique);
+
+ fill_fid_trans(&childEntry->fid);
+
+#if 0
+ ReleaseWriteLock(&childEntry->lock);
+#endif
+
+
+ ret = volcache_getbyid (childEntry->fid.fid.Volume,
+ childEntry->fid.Cell,
+ ce,
+ &childEntry->volume,
+ &type);
+
+ recon_hashtabadd(childEntry);
+
+ arla_log(ADEBDISCONN,
+ "reconnect: create after volcache_getbyid, Cell=0x%x, "
+ "fid.Volume= 0x%x, fid .Vnode=0x%x, fid.Unique=0x%x",
+ childEntry->fid.Cell,
+ childEntry->fid.fid.Volume,
+ childEntry->fid.fid.Vnode,
+ childEntry->fid.fid.Unique);
+
+/* SWW Qiyue 30: add the new file entry in dir */
+ arla_warnx (ADEBDISCONN,"reconnect_rename: we add the new one "
+ "volumn=0x%x,vnode=0x%x,unique=0x%x",
+ parentEntry->fid.fid.Volume,
+ parentEntry->fid.fid.Vnode,
+ parentEntry->fid.fid.Unique);
+
+ adir_creat (parentEntry, name, childEntry->fid.fid);
+
+ childEntry->status = fetch_attr;
+
+ childEntry->flags.attrp = TRUE;
+ childEntry->flags.kernelp = TRUE;
+
+ childEntry->flags.datap = TRUE;
+ childEntry->tokens |= XFS_ATTR_R | XFS_DATA_R | XFS_DATA_W;
+
+ volcache_update_volsync (parentEntry->volume, parentEntry->volsync);
+
+
+
+/*SWW Qiyue 28: Set the host for child entry */
+
+ childEntry->host = rx_HostOf (rx_PeerOf (conn->connection));
+ assert(childEntry->host);
+
+/*SWW Qiyue 29: */
+ arla_warnx (ADEBDISCONN,
+ "Replace fid.Volume=0x%x,Vnode=0x%x,Unique=0x%x with "
+ "Volume=0x%x,Vnode=0x%x,Unqiue=0x%x",
+ fakeFid.fid.Volume,
+ fakeFid.fid.Vnode,
+ fakeFid.fid.Unique,
+ childEntry->fid.fid.Volume,
+ childEntry->fid.fid.Vnode,
+ childEntry->fid.fid.Unique);
+
+ update_kernelfid(fakeFid, childEntry->fid);
+
+ conv_dir(parentEntry, ce, 0, &cache_handle, tmp, sizeof(tmp));
+
+ ReleaseWriteLock(&childEntry->lock);
+
+ out:
+
+ ReleaseWriteLock(&parentEntry->lock);
+ ReleaseWriteLock(&childEntry->lock);
+ free_fs_server_context(&context);
+ cred_free(ce);
+ return ret;
+}
+
+/*
+ *
+ */
+
+int reconnect_mkdir(struct vcache *parent, struct vcache *curdir,
+ AFSStoreStatus *store_status, char *name)
+{
+ ConnCacheEntry *conn;
+ fs_server_context context;
+ CredCacheEntry *ce;
+ VenusFid *parent_fid;
+ VenusFid *child_fid;
+ VenusFid fakeFid;
+
+ FCacheEntry *parentEntry, *childEntry, *tempEntry, *tempparEntry;
+ Result tempres;
+ Result res;
+ int ret = 0;
+ int tempret = 0;
+ struct timeval tv;
+ char tmp[5];
+
+ AFSFid Outfid; /* Ba Wu: These are used to get the info from FS*/
+ AFSFetchStatus fetch_attr;
+ AFSFetchStatus status;
+ AFSCallBack callback;
+ AFSVolSync volsync;
+ xfs_cache_handle cache_handle;
+ int32_t type;
+
+ parent_fid = &(parent->fid); /* points to the VenusFid structure */
+ child_fid = &(curdir->fid);
+ fakeFid = *child_fid;
+
+ parent_fid = fid_translate(parent_fid);
+
+ ce = cred_get (parent->fid.Cell, parent->cred.pag, CRED_ANY);
+ assert (ce != NULL);
+
+ ret = fcache_find (&parentEntry, *parent_fid);
+ assert (ret == 0);
+
+ tempparEntry = parentEntry;
+
+/*Ba ba: used to check whether name can be find Deleted !!!
+ ReleaseWriteLock(&parentEntry->lock);
+ tempret = adir_lookup (parentEntry->fid , name , &foo_fid , ce); */
+/*Ba ba: used to check whether name can be find Deleted !!! */
+
+ /*Ba Wu Remove the dir name from itsparent dir */
+ tempret = adir_remove(parentEntry,name);
+ conn = find_first_fs (parentEntry, ce, &context);
+
+ if (conn == NULL) {
+ arla_log (ADEBDISCONN,"Cannot make this connection");
+ res.res = ENOMEM;
+ goto out;
+ }
+
+ ret = fcache_find(&childEntry, *child_fid);/*Ba Wu: remove the newly created dir */
+ assert (ret == 0);
+
+ recon_hashtabdel(childEntry);
+
+ alloc_fid_trans(&childEntry->fid);
+
+ gettimeofday(&tv, NULL);
+
+ ret = RXAFS_MakeDir (conn->connection,
+ &parentEntry->fid.fid,
+ name,
+ store_status,
+ &Outfid,
+ &fetch_attr,
+ &status,
+ &callback,
+ &volsync);
+
+ if (ret) {
+ arla_log (ADEBDISCONN, "Could not CreateFile: %s (%d)",
+ koerr_gettext(ret), ret);
+ goto out;
+ }
+
+ parentEntry->status = status;
+ parentEntry->callback = callback;
+ parentEntry->callback.ExpirationTime += tv.tv_sec;
+ parentEntry->volsync = volsync;
+
+ childEntry->fid.Cell = parentEntry->fid.Cell;
+ childEntry->fid.fid = Outfid;
+ childEntry->status = fetch_attr;
+ childEntry->flags.attrp = TRUE;
+ childEntry->flags.kernelp = TRUE;
+ childEntry->flags.datap = TRUE;
+ childEntry->tokens |= XFS_ATTR_R | XFS_DATA_R | XFS_DATA_W;
+
+ fill_fid_trans(&childEntry->fid);
+
+ ret = volcache_getbyid (childEntry->fid.fid.Volume,
+ childEntry->fid.Cell,
+ ce,
+ &childEntry->volume,
+ &type);
+
+ recon_hashtabadd(childEntry);
+
+/*Ba ba: Need to change later!!! */
+#if 0
+ ReleaseWriteLock(&tempparEntry->lock);
+ tempret = adir_changefid (tempparEntry->fid ,name, &Outfid, ce);
+ ReleaseWriteLock(&tempparEntry->lock);
+ tempret = adir_lookup (tempparEntry->fid ,name, &foo_fid, ce);
+#endif
+
+ tempret = adir_creat (parentEntry, name, childEntry->fid.fid);
+
+ tempret = adir_mkdir (childEntry, childEntry->fid.fid,parentEntry->fid.fid);
+
+ childEntry->host = rx_HostOf (rx_PeerOf (conn->connection));
+ assert(childEntry->host);
+
+ update_kernelfid(fakeFid, childEntry->fid);
+
+ tempres = conv_dir(parentEntry, ce, 0, &cache_handle,
+ tmp, sizeof(tmp));
+
+ ReleaseWriteLock(&childEntry->lock);
+
+ /*SWW Qiyue 29: This should be deleted later */
+ ret = fcache_find (&tempEntry, childEntry->fid);
+
+ assert (ret == 0);
+ assert (tempEntry == NULL);
+
+ out:
+
+ ReleaseWriteLock(&parentEntry->lock);
+ ReleaseWriteLock(&childEntry->lock);
+ free_fs_server_context(&context);
+ cred_free(ce);
+ return ret;
+}
+
+/*
+ *
+ */
+
+int reconnect_link(struct vcache *parent, struct vcache *existing,
+ char *name)
+{
+ ConnCacheEntry *conn;
+ fs_server_context context;
+ CredCacheEntry *ce;
+ VenusFid *parent_fid;
+ VenusFid *existing_fid;
+ char tmp[5];
+ int ret = 0;
+ FCacheEntry *dir_entry,*existing_entry;
+ Result res;
+
+ AFSFetchStatus new_status;
+ AFSFetchStatus status;
+ AFSVolSync volsync;
+ xfs_cache_handle cache_handle;
+
+
+ parent_fid = &(parent->fid);
+ existing_fid = &(existing->fid);
+
+ parent_fid = fid_translate(parent_fid);
+
+ ce = cred_get (parent->fid.Cell, parent->cred.pag, CRED_ANY);
+ assert (ce != NULL);
+
+ ret = fcache_find (&dir_entry, *parent_fid);
+ assert (ret == 0);
+
+ ret = fcache_find (&existing_entry, *existing_fid);
+ assert (ret == 0);
+
+ conn = find_first_fs (dir_entry, ce, &context);
+
+ if (conn == NULL) {
+ arla_log (ADEBDISCONN,"Cannot make this connection");
+ res.res = ENOMEM;
+ goto out;
+ }
+
+ ret = RXAFS_Link (conn->connection,
+ &dir_entry->fid.fid,
+ name,
+ &existing_entry->fid.fid,
+ &new_status,
+ &status,
+ &volsync);
+ if (ret) {
+ arla_warn (ADEBFCACHE, ret, "Link");
+ goto out;
+ }
+
+ dir_entry->status = status;
+ dir_entry->volsync = volsync;
+
+ existing_entry->status = new_status;
+
+ volcache_update_volsync (dir_entry->volume, dir_entry->volsync);
+
+ res = conv_dir (dir_entry, ce, 0, &cache_handle, tmp, sizeof(tmp));
+
+ out:
+ ReleaseWriteLock(&dir_entry->lock);
+ ReleaseWriteLock(&existing_entry->lock);
+ free_fs_server_context (&context);
+ return ret;
+}
+
+/*
+ *
+ */
+
+int reconnect_symlink(struct vcache *parent, struct vcache *child,
+ AFSStoreStatus *store_attr, char *name,
+ char *contents)
+{
+ ConnCacheEntry *conn;
+ fs_server_context context;
+ CredCacheEntry *ce;
+ VenusFid *parent_fid, *child_fid, fakeFid;
+ char tmp[5];
+ int ret = 0;
+ FCacheEntry *dir_entry, *childEntry;
+ Result res;
+
+ AFSFetchStatus fetch_attr, new_status;
+ AFSVolSync volsync;
+ xfs_cache_handle cache_handle;
+ int32_t type;
+
+ parent_fid = &(parent->fid);
+ child_fid = &(child->fid);
+ fakeFid = *child_fid;
+ parent_fid = fid_translate(parent_fid);
+
+ ce = cred_get (parent->fid.Cell, parent->cred.pag, CRED_ANY);
+ assert (ce != NULL);
+
+ ret = fcache_find (&dir_entry, *parent_fid);
+ assert (ret == 0);
+
+ adir_remove(dir_entry,name);
+
+ ret = fcache_find (&childEntry, *child_fid);
+ assert (ret == 0);
+
+ recon_hashtabdel(childEntry);
+
+ assert(ret==0);
+ conn = find_first_fs (dir_entry, ce, &context);
+
+ if (conn == NULL) {
+ arla_log (ADEBDISCONN,"Cannot make this connection");
+ goto out;
+ }
+
+ alloc_fid_trans(&childEntry->fid);
+
+ ret = RXAFS_Symlink (conn->connection,
+ &dir_entry->fid.fid,
+ name,
+ contents,
+ store_attr,
+ &(childEntry->fid.fid),
+ &fetch_attr,
+ &new_status,
+ &volsync);
+ if (ret) {
+ arla_warn (ADEBFCACHE, ret, "Symlink");
+ goto out;
+ }
+
+ child_fid->Cell = dir_entry->fid.Cell;
+
+ fill_fid_trans (&childEntry->fid);
+ ret = volcache_getbyid (childEntry->fid.fid.Volume,
+ childEntry->fid.Cell,
+ ce,
+ &childEntry->volume,
+ &type);
+
+ recon_hashtabadd (childEntry);
+
+ adir_creat(dir_entry, name, childEntry->fid.fid);
+
+ childEntry->status = fetch_attr;
+ childEntry->flags.attrp = TRUE;
+ childEntry->flags.kernelp = TRUE;
+ childEntry->tokens |= XFS_ATTR_R;
+ volcache_update_volsync (dir_entry->volume, dir_entry->volsync);
+
+ childEntry->host = rx_HostOf (rx_PeerOf (conn->connection));
+ assert(childEntry->host);
+
+ update_kernelfid(fakeFid, childEntry->fid);
+ res = conv_dir (dir_entry, ce, 0, &cache_handle, tmp, sizeof(tmp));
+
+ out:
+ ReleaseWriteLock(&dir_entry->lock);
+ ReleaseWriteLock(&childEntry->lock);
+ free_fs_server_context(&context);
+ cred_free(ce);
+ return ret;
+}
+
diff --git a/usr.sbin/afs/src/arlad/reconnect.h b/usr.sbin/afs/src/arlad/reconnect.h
new file mode 100644
index 00000000000..de1b829a26e
--- /dev/null
+++ b/usr.sbin/afs/src/arlad/reconnect.h
@@ -0,0 +1,39 @@
+/* $OpenBSD: reconnect.h,v 1.1 1999/04/30 01:59:10 art Exp $ */
+/* COPYRIGHT (C) 1998
+ * THE REGENTS OF THE UNIVERSITY OF MICHIGAN
+ * ALL RIGHTS RESERVED
+ *
+ * PERMISSION IS GRANTED TO USE, COPY, CREATE DERIVATIVE WORKS
+ * AND REDISTRIBUTE THIS SOFTWARE AND SUCH DERIVATIVE WORKS
+ * FOR ANY PURPOSE, SO LONG AS THE NAME OF THE UNIVERSITY OF
+ * MICHIGAN IS NOT USED IN ANY ADVERTISING OR PUBLICITY
+ * PERTAINING TO THE USE OR DISTRIBUTION OF THIS SOFTWARE
+ * WITHOUT SPECIFIC, WRITTEN PRIOR AUTHORIZATION. IF THE
+ * ABOVE COPYRIGHT NOTICE OR ANY OTHER IDENTIFICATION OF THE
+ * UNIVERSITY OF MICHIGAN IS INCLUDED IN ANY COPY OF ANY
+ * PORTION OF THIS SOFTWARE, THEN THE DISCLAIMER BELOW MUST
+ * ALSO BE INCLUDED.
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
+ * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
+ * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
+ * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
+ * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+ * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
+ * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
+ * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGES.
+ */
+
+/* $KTH: reconnect.h,v 1.3 1998/12/21 21:54:43 assar Exp $ */
+
+#ifndef _RECONNECT_H
+#define _RECONNECT_H
+
+void
+do_replay(char *log_file, int log_entries, VenusFid *changed_fid);
+
+#endif /* _RECONNECT_H */
diff --git a/usr.sbin/afs/src/lib/ko/vlmisc.c b/usr.sbin/afs/src/lib/ko/vlmisc.c
new file mode 100644
index 00000000000..4db702f96b3
--- /dev/null
+++ b/usr.sbin/afs/src/lib/ko/vlmisc.c
@@ -0,0 +1,92 @@
+/* $OpenBSD: vlmisc.c,v 1.1 1999/04/30 01:59:11 art Exp $ */
+/*
+ * Copyright (c) 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the Kungliga Tekniska
+ * Högskolan and its contributors.
+ *
+ * 4. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "ko_locl.h"
+
+RCSID("$KTH: vlmisc.c,v 1.1 1999/03/03 15:33:21 assar Exp $");
+
+/*
+ * Convert old style vldbentry `old` to newer vldbNentry style `new'
+ */
+
+void
+vldb2vldbN (const vldbentry *old, nvldbentry *new)
+{
+ int i;
+
+ strncpy (new->name, old->name, VLDB_MAXNAMELEN);
+ new->name[VLDB_MAXNAMELEN-1] = '\0';
+ if (old->nServers > MAXNSERVERS)
+ new->nServers = MAXNSERVERS;
+ else
+ new->nServers = old->nServers;
+
+ for (i = 0; i < new->nServers ; i++) {
+ new->serverNumber[i] = old->serverNumber[i];
+ new->serverPartition[i] = old->serverPartition[i];
+ new->serverFlags[i] = old->serverFlags[i];
+ }
+ for (i = 0; i < MAXTYPES ; i++)
+ new->volumeId[i] = old->volumeId[i];
+ new->cloneId = old->cloneId;
+ new->flags = old->flags;
+}
+
+void
+volintInfo2xvolintInfo (const volintInfo *old, xvolintInfo *new)
+{
+ memset (new, 0, sizeof(*new));
+ strcpy (new->name, old->name);
+ new->volid = old->volid;
+ new->type = old->type;
+ new->backupID = old->backupID;
+ new->parentID = old->parentID;
+ new->cloneID = old->cloneID;
+ new->status = old->status;
+ new->copyDate = old->copyDate;
+ new->inUse = old->inUse;
+ new->creationDate = old->creationDate;
+ new->accessDate = old->accessDate;
+ new->updateDate = old->updateDate;
+ new->backupDate = old->backupDate;
+ new->dayUse = old->dayUse;
+ new->filecount = old->filecount;
+ new->maxquota = old->maxquota;
+ new->size = old->size;
+}
diff --git a/usr.sbin/afs/src/lwp/plwp.c b/usr.sbin/afs/src/lwp/plwp.c
new file mode 100644
index 00000000000..62509a78b1e
--- /dev/null
+++ b/usr.sbin/afs/src/lwp/plwp.c
@@ -0,0 +1,939 @@
+/* $OpenBSD: plwp.c,v 1.1 1999/04/30 01:59:13 art Exp $ */
+/* This version of the code is derived from the Coda version of the LWP
+ * library, which can be compiled as a wrapper around Mach cthreads
+ */
+/*
+****************************************************************************
+* Copyright IBM Corporation 1988, 1989 - All Rights Reserved *
+* *
+* Permission to use, copy, modify, and distribute this software and its *
+* documentation for any purpose and without fee is hereby granted, *
+* provided that the above copyright notice appear in all copies and *
+* that both that copyright notice and this permission notice appear in *
+* supporting documentation, and that the name of IBM not be used in *
+* advertising or publicity pertaining to distribution of the software *
+* without specific, written prior permission. *
+* *
+* IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL *
+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL IBM *
+* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY *
+* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER *
+* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING *
+* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
+****************************************************************************
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* allocate externs here */
+#define LWP_KERNEL
+
+#include <lwp.h>
+
+RCSID("$KTH: plwp.c,v 1.2 1999/02/02 00:47:16 assar Exp $");
+
+#ifdef AFS_AIX32_ENV
+#include <ulimit.h>
+#include <sys/errno.h>
+#include <sys/user.h>
+#include <sys/pseg.h>
+#include <sys/core.h>
+#pragma alloca
+#endif
+
+#ifndef MAX
+#define MAX(a,b) (((a)>(b))?(a):(b))
+#endif
+
+extern char PRE_Block; /* from preempt.c */
+
+#define ON 1
+#define OFF 0
+#define TRUE 1
+#define FALSE 0
+#define READY 2
+#define WAITING 3
+#define DESTROYED 4
+#define QWAITING 5
+#define MAXINT (~(1<<((sizeof(int)*8)-1)))
+#define MINSTACK 44
+
+
+/* Debugging macro */
+#ifdef DEBUG
+#define Debug(level, msg)\
+ if (lwp_debug && lwp_debug >= level) {\
+ printf("***LWP (%p): ", lwp_cpptr);\
+ printf msg;\
+ putchar('\n');\
+ }
+
+#else
+#define Debug(level, msg)
+#endif
+
+/* Prototypes */
+static void Abort_LWP(char *msg) ;
+static void Dispatcher(void);
+static void Create_Process_Part2(PROCESS temp);
+static void purge_dead_pcbs(void) ;
+static void Dispose_of_Dead_PCB (PROCESS cur) ;
+static void Free_PCB(PROCESS pid) ;
+static void Exit_LWP();
+static void Initialize_PCB(PROCESS temp, int priority, char *stack,
+ int stacksize, void (*ep)() , char *parm,
+ char *name) ;
+static int Internal_Signal(register char *event) ;
+char (*RC_to_ASCII());
+
+#define MAX_PRIORITIES (LWP_MAX_PRIORITY+1)
+
+struct QUEUE {
+ PROCESS head;
+ int count;
+} runnable[MAX_PRIORITIES], blocked;
+/*
+ * Invariant for runnable queues: The head of each queue points to the
+ * currently running process if it is in that queue, or it points to the
+ * next process in that queue that should run.
+ */
+
+/* special user-tweakable option for AIX */
+int lwp_MaxStackSize = 32768;
+int lwp_MaxStackSeen = 0;
+
+int lwp_nextindex = 0;
+
+/* Iterator macro */
+#define for_all_elts(var, q, body)\
+ {\
+ register PROCESS var, _NEXT_;\
+ register int _I_;\
+ for (_I_=q.count, var = q.head; _I_>0; _I_--, var=_NEXT_) {\
+ _NEXT_ = var -> next;\
+ body\
+ }\
+ }
+
+static struct lwp_ctl *lwp_init = 0;
+
+static void Dump_One_Process(PROCESS pid);
+static void Dump_Processes();
+static void Delete_PCB(register PROCESS pid);
+static void Free_PCB(PROCESS pid);
+static void Cal_Highest_runnable_priority();
+static int InitializeProcessSupport(int, PROCESS *);
+
+PROCESS lwp_cpptr;
+
+/* The global Highest_runnable_priority is only needed in NEW lwp.
+ But it gets set within a for_all_elts() instance in
+ InternalSignal(). */
+int Highest_runnable_priority; /* global variable for max priority */
+
+int Proc_Running; /* indicates forked proc got control */
+
+pthread_mutex_t run_sem, ct_mutex;
+
+static void
+lwpremove(register PROCESS p, register struct QUEUE *q)
+{
+ /* Special test for only element on queue */
+ if (q->count == 1)
+ q -> head = NULL;
+ else {
+ /* Not only element, do normal remove */
+ p -> next -> prev = p -> prev;
+ p -> prev -> next = p -> next;
+ }
+ /* See if head pointing to this element */
+ if (q->head == p) q -> head = p -> next;
+ q->count--;
+ Debug(0, ("removing, count now %d", q->count));
+ p -> next = p -> prev = NULL;
+}
+
+static void
+lwpinsert(register PROCESS p, register struct QUEUE *q)
+{
+ if (q->head == NULL) { /* Queue is empty */
+ q -> head = p;
+ p -> next = p -> prev = p;
+ } else { /* Regular insert */
+ p -> prev = q -> head -> prev;
+ q -> head -> prev -> next = p;
+ q -> head -> prev = p;
+ p -> next = q -> head;
+ }
+ q->count++;
+ Debug(0, ("inserting, count now %d", q->count));
+}
+
+static void
+lwpmove(PROCESS p, struct QUEUE *from, struct QUEUE *to)
+{
+ lwpremove(p, from);
+ lwpinsert(p, to);
+}
+
+int
+LWP_TerminateProcessSupport() /* terminate all LWP support */
+{
+ register int i;
+
+ Debug(0, ("Entered Terminate_Process_Support"));
+ if (lwp_init == NULL) return LWP_EINIT;
+ /* free all space allocated */
+ for (i=0; i<MAX_PRIORITIES; i++)
+ for_all_elts(cur, runnable[i], { Free_PCB(cur);})
+ for_all_elts(cur, blocked, { Free_PCB(cur);})
+ free((char *)lwp_init);
+ lwp_init = NULL;
+ return LWP_SUCCESS;
+}
+
+int
+LWP_GetRock(int Tag, char **Value)
+{
+ /* Obtains the pointer Value associated with the rock Tag of this LWP.
+ Returns:
+ LWP_SUCCESS if specified rock exists and Value has been filled
+ LWP_EBADROCK rock specified does not exist
+ */
+ register int i;
+ register struct rock *ra;
+
+ ra = lwp_cpptr->rlist;
+
+ for (i = 0; i < lwp_cpptr->rused; i++)
+ if (ra[i].tag == Tag) {
+#ifdef PTHREAD_GETSPECIFIC_TWOARG
+ pthread_getspecific(ra[i].val, Value);
+#else
+ *Value = pthread_getspecific(ra[i].val);
+#endif
+ /**Value = ra[i].value;*/
+ return(LWP_SUCCESS);
+ }
+ return(LWP_EBADROCK);
+}
+
+
+int
+LWP_NewRock(int Tag, char *Value)
+{
+ /* Finds a free rock and sets its value to Value.
+ Return codes:
+ LWP_SUCCESS Rock did not exist and a new one was used
+ LWP_EBADROCK Rock already exists.
+ LWP_ENOROCKS All rocks are in use.
+
+ From the above semantics, you can only set a rock value once.
+ This is specifically to prevent multiple users of the LWP
+ package from accidentally using the same Tag value and
+ clobbering others. You can always use one level of
+ indirection to obtain a rock whose contents can change. */
+
+ register int i;
+ register struct rock *ra; /* rock array */
+
+ ra = lwp_cpptr->rlist;
+
+ /* check if rock has been used before */
+ for (i = 0; i < lwp_cpptr->rused; i++)
+ if (ra[i].tag == Tag) return(LWP_EBADROCK);
+
+ /* insert new rock in rock list and increment count of rocks */
+ if (lwp_cpptr->rused < MAXROCKS) {
+ ra[lwp_cpptr->rused].tag = Tag;
+#ifdef HAVE_PTHREAD_KEYCREATE
+ if (pthread_keycreate(&ra[lwp_cpptr->rused].val, NULL))
+#else
+ if (pthread_key_create(&ra[lwp_cpptr->rused].val, NULL))
+#endif
+ return(LWP_EBADROCK);
+ if (pthread_setspecific(ra[lwp_cpptr->rused].val, Value))
+ return(LWP_EBADROCK);
+ /* ra[lwp_cpptr->rused].value = Value; */
+ lwp_cpptr->rused++;
+ return(LWP_SUCCESS);
+ }
+ else return(LWP_ENOROCKS);
+}
+
+static void
+Dispose_of_Dead_PCB(PROCESS cur)
+{
+
+ Debug(0, ("Entered Dispose_of_Dead_PCB"));
+ Delete_PCB(cur);
+ Free_PCB(cur);
+}
+
+int
+LWP_CurrentProcess(PROCESS *pid)
+{
+ Debug(0, ("Entered Current_Process"));
+ if (lwp_init) {
+ *pid = lwp_cpptr;
+ return LWP_SUCCESS;
+ } else
+ return LWP_EINIT;
+}
+
+
+int
+LWP_GetProcessPriority(PROCESS pid, int *priority)
+{
+ Debug(0, ("Entered Get_Process_Priority"));
+ if (lwp_init) {
+ *priority = pid -> priority;
+ return 0;
+ } else
+ return LWP_EINIT;
+}
+
+int
+LWP_WaitProcess(char *event)
+{
+ char *tempev[2];
+
+ Debug(0, ("Entered Wait_Process"));
+ if (event == NULL) return LWP_EBADEVENT;
+ tempev[0] = event;
+ tempev[1] = NULL;
+ return LWP_MwaitProcess(1, tempev);
+}
+
+static void
+Delete_PCB(register PROCESS pid)
+{
+ Debug(0, ("Entered Delete_PCB"));
+ lwpremove(pid, (pid->blockflag || pid->status==WAITING ||
+ pid->status==DESTROYED ? &blocked
+ : &runnable[pid->priority]));
+}
+
+static void
+purge_dead_pcbs()
+{
+ for_all_elts(cur, blocked, { if (cur->status == DESTROYED)
+ Dispose_of_Dead_PCB(cur); })
+}
+
+static void
+Exit_LWP()
+{
+ exit (-1);
+}
+
+static void
+Dump_Processes()
+{
+ if (lwp_init) {
+ register int i;
+ for (i=0; i<MAX_PRIORITIES; i++)
+ for_all_elts(x, runnable[i], {
+ printf("[Priority %d]\n", i);
+ Dump_One_Process(x);
+ })
+ for_all_elts(x, blocked, { Dump_One_Process(x); })
+ } else
+ printf("***LWP: LWP support not initialized\n");
+}
+
+char *
+LWP_Name()
+{
+ return(lwp_cpptr->name);
+}
+
+int
+LWP_Index()
+{
+ return(lwp_cpptr->index);
+}
+
+int
+LWP_HighestIndex()
+{
+ return(lwp_nextindex-1);
+}
+
+/* A process calls this routine to wait until somebody signals it.
+ * LWP_QWait removes the calling process from the runnable queue
+ * and makes the process sleep until some other process signals via LWP_QSignal
+ */
+int
+LWP_QWait()
+{
+ PROCESS old_cpptr;
+
+ Debug(0, ("LWP_QWait: %s is going to QWait\n", lwp_cpptr->name));
+ lwp_cpptr->status = QWAITING;
+ if (runnable[lwp_cpptr->priority].count == 0)
+ Cal_Highest_runnable_priority();
+
+ old_cpptr = lwp_cpptr;
+
+ /* wake up next lwp */
+ lwp_cpptr = runnable[Highest_runnable_priority].head;
+ lwpremove(lwp_cpptr, &runnable[Highest_runnable_priority]);
+ timerclear(&lwp_cpptr->lastReady);
+ pthread_mutex_lock(&ct_mutex);
+ Debug(0, ("LWP_QWait:%s going to wake up %s \n", old_cpptr->name,
+ lwp_cpptr->name));
+ pthread_cond_signal(&lwp_cpptr->c);
+
+ /* sleep on your own condition */
+ Debug(0, ("LWP_QWait:%s going to wait on own condition \n",
+ old_cpptr->name));
+ pthread_cond_wait(&old_cpptr->c, &ct_mutex);
+ pthread_mutex_unlock(&ct_mutex);
+
+ lwp_cpptr = old_cpptr;
+
+ /* return only if calling process' priority is the highest */
+ if (lwp_cpptr->priority < Highest_runnable_priority)
+ Dispatcher();
+ return LWP_SUCCESS;
+}
+
+
+/* signal the PROCESS pid - by adding it to the runnable queue */
+int
+LWP_QSignal(PROCESS pid)
+{
+ if (pid->status == QWAITING) {
+ Debug(0, ("LWP_Qsignal: %s is going to QSignal %s\n", lwp_cpptr->name,
+ pid->name));
+ pid->status = READY;
+ lwpinsert(pid, &runnable[pid->priority]);
+ Debug(0, ("LWP_QSignal: Just inserted %s into runnable queue\n",
+ pid->name));
+ gettimeofday(&pid->lastReady, 0);
+ Highest_runnable_priority =
+ MAX(Highest_runnable_priority, pid->priority);
+ Debug(0, ("%s priority= %d; HRP = %d; Signalled process pri = %d",
+ lwp_cpptr->name, lwp_cpptr->priority,
+ Highest_runnable_priority, pid->priority));
+ return LWP_SUCCESS;
+ }
+ else return LWP_ENOWAIT;
+}
+
+
+int
+LWP_CreateProcess(void (*ep)(), int stacksize, int priority,
+ char *parm, char *name, PROCESS *pid)
+{
+ PROCESS temp;
+ pthread_t ct;
+ pthread_attr_t cta;
+ PROCESS old_cpptr;
+ int retval;
+
+ Debug(0, ("Entered LWP_CreateProcess to create %s at priority %d\n",
+ name, priority));
+ old_cpptr = lwp_cpptr;
+ /* Throw away all dead process control blocks */
+ purge_dead_pcbs();
+
+ if (lwp_init) {
+ /* allocate the memory for the pcb - check for malloc errors */
+ temp = (PROCESS)malloc (sizeof (struct lwp_pcb));
+ if (temp == NULL) {
+ Dispatcher();
+ return LWP_ENOMEM;
+ }
+
+ /* check priorities */
+ if (priority < 0 || priority >= MAX_PRIORITIES) {
+ Dispatcher();
+ return LWP_EBADPRI;
+ }
+
+ Initialize_PCB(temp, priority, NULL, 0, ep, parm, name);
+
+ /* make the process runnable by placing it in the runnable q */
+ lwpinsert(temp, &runnable[priority]);
+ gettimeofday(&temp->lastReady, 0);
+
+ if (PRE_Block != 0) Abort_LWP("PRE_Block not 0");
+
+ PRE_Block = 1;
+ Proc_Running = FALSE; /* sem set true by forked process */
+
+ pthread_attr_init(&cta);
+#ifdef _POSIX_THREAD_ATTR_STACKSIZE
+ pthread_attr_setstacksize(&cta, stacksize);
+#endif
+ retval = pthread_create(&ct, &cta, (void *)Create_Process_Part2, temp);
+ if (!retval) {
+ temp->a = cta;
+ pthread_detach(ct);
+
+ /* check if max priority has changed */
+ Highest_runnable_priority = MAX(Highest_runnable_priority, priority);
+
+ pthread_mutex_lock(&run_sem);
+ Debug(0, ("Before creating process yields Proc_Running = %d\n",
+ Proc_Running));
+ while( !Proc_Running ){
+ pthread_mutex_unlock(&run_sem);
+#if defined(HAVE_THR_YIELD)
+ thr_yield();
+#elif defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
+ sched_yield();
+#else
+ pthread_yield();
+#endif
+ pthread_mutex_lock(&run_sem);
+ Debug(0,("After creating proc yields and gets back control Proc_Running = %d\n",
+ Proc_Running));
+ }
+ pthread_mutex_unlock(&run_sem);
+
+ lwp_cpptr = old_cpptr;
+
+ Dispatcher();
+ *pid = temp;
+ return LWP_SUCCESS;
+ }
+ } else {
+ pthread_attr_destroy(&cta);
+ }
+ return LWP_EINIT;
+}
+
+int
+LWP_DestroyProcess(PROCESS pid)
+{
+ void *t;
+
+ Debug(0, ("Entered Destroy_Process"));
+ if (lwp_init) {
+ pthread_attr_destroy(&pid->a);
+ if (lwp_cpptr == pid){
+ /* kill myself */
+ pid->status = DESTROYED;
+ Free_PCB(pid);
+ Cal_Highest_runnable_priority();
+
+ /* Calculate next runnable lwp and signal it */
+ lwp_cpptr = runnable[Highest_runnable_priority].head;
+ lwpremove(lwp_cpptr, &runnable[Highest_runnable_priority]);
+
+ pthread_mutex_lock(&ct_mutex);
+ pthread_cond_signal(&lwp_cpptr->c);
+ pthread_mutex_unlock(&ct_mutex);
+ pthread_exit(t);
+ } else {
+ /* kill some other process - mark status destroyed -
+ if process is blocked, it will be purged on next create proc;
+ if it is runnable the dispatcher will kill it */
+ pid->status = DESTROYED ;
+ Dispatcher();
+ }
+ return LWP_SUCCESS ;
+ } else
+ return LWP_EINIT;
+}
+
+int
+LWP_DispatchProcess() /* explicit voluntary preemption */
+{
+ Debug(0, ("Entered Dispatch_Process"))
+ if (lwp_init) {
+ Dispatcher();
+ return LWP_SUCCESS;
+ } else
+ return LWP_EINIT;
+}
+
+int
+LWP_Init(int version, int priority, PROCESS *pid)
+{
+ if (version != LWP_VERSION)
+ {
+ fprintf(stderr, "**** FATAL ERROR: LWP VERSION MISMATCH ****\n");
+ exit(-1);
+ }
+ else return(InitializeProcessSupport(priority, pid));
+}
+
+int
+LWP_InitializeProcessSupport(int priority, PROCESS *pid)
+{
+ return(InitializeProcessSupport(priority, pid));
+}
+
+static int
+InitializeProcessSupport(int priority, PROCESS *pid)
+{
+ PROCESS temp;
+ register int i;
+
+ Debug(0, ("Entered InitializeProcessSupport"));
+ if (lwp_init != NULL) return LWP_SUCCESS;
+
+ /* check priorities and set up running and blocked queues */
+ if (priority >= MAX_PRIORITIES) return LWP_EBADPRI;
+ for (i=0; i<MAX_PRIORITIES; i++) {
+ runnable[i].head = NULL;
+ runnable[i].count = 0;
+ }
+ blocked.head = NULL;
+ blocked.count = 0;
+ lwp_init = (struct lwp_ctl *) malloc(sizeof(struct lwp_ctl));
+ temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
+ if (lwp_init == NULL || temp == NULL)
+ Abort_LWP("Insufficient Storage to Initialize LWP Support");
+
+ /* check parameters */
+ Initialize_PCB(temp, priority, NULL, 0, NULL, NULL,"Main Process");
+ gettimeofday(&temp->lastReady, 0);
+
+ Highest_runnable_priority = priority;
+
+ /* initialize mutex and semaphore */
+ Proc_Running = TRUE;
+ pthread_mutex_init(&run_sem, NULL);
+ pthread_mutex_init(&ct_mutex, NULL);
+
+ lwp_cpptr = temp;
+ Dispatcher();
+ *pid = temp;
+ return LWP_SUCCESS;
+}
+
+int
+LWP_INTERNALSIGNAL(void *event, int yield)
+{
+ Debug(0, ("Entered LWP_SignalProcess, yield=%d", yield));
+ if (lwp_init) {
+ int rc;
+ rc = Internal_Signal(event);
+ if (yield) {
+ Cal_Highest_runnable_priority();
+ Debug(0, ("hipri=%d", Highest_runnable_priority));
+ Dispatcher();
+ }
+ return rc;
+ } else
+ return LWP_EINIT;
+}
+
+int
+LWP_MwaitProcess(int wcount, char *evlist[]) /* wait on m of n events */
+{
+ register int ecount, i;
+ PROCESS old_cpptr;
+
+ Debug(0, ("Entered Mwait_Process [waitcnt = %d]", wcount));
+ if (evlist == NULL) {
+ Dispatcher();
+ return LWP_EBADCOUNT;
+ }
+
+ /* count # of events in eventlist */
+ for (ecount = 0; evlist[ecount] != NULL; ecount++) ;
+ if (ecount == 0) {
+ Dispatcher();
+ return LWP_EBADCOUNT;
+ }
+
+ if (lwp_init) {
+ /* check for illegal counts */
+ if (wcount>ecount || wcount<0) {
+ Dispatcher();
+ return LWP_EBADCOUNT;
+ }
+
+ /* reallocate eventlist if new list has more elements than before */
+ if (ecount > lwp_cpptr->eventlistsize) {
+ lwp_cpptr->eventlist =
+ (char **)realloc((char *)lwp_cpptr->eventlist,
+ ecount*sizeof(char *));
+ lwp_cpptr->eventlistsize = ecount;
+ }
+
+ /* place events in eventlist of the pcb */
+ for (i=0; i<ecount; i++) lwp_cpptr -> eventlist[i] = evlist[i];
+
+ /* if there are any events to wait on then set status to
+ WAITING and place the pcb in blocked queue */
+ if (wcount > 0) {
+ lwp_cpptr -> status = WAITING;
+ lwpinsert(lwp_cpptr, &blocked);
+ }
+ lwp_cpptr -> wakevent = 0; /* index of eventid causing wakeup */
+ lwp_cpptr -> waitcnt = wcount;
+ lwp_cpptr -> eventcnt = ecount;
+ if (runnable[lwp_cpptr->priority].count == 0)
+ Cal_Highest_runnable_priority();
+ old_cpptr = lwp_cpptr;
+
+ /* wake up next lwp */
+ lwp_cpptr = runnable[Highest_runnable_priority].head;
+ lwpremove(lwp_cpptr, &runnable[Highest_runnable_priority]);
+ timerclear(&lwp_cpptr->lastReady);
+ Debug(0, ("WaitProcess: %s Going to signal %s \n",
+ old_cpptr->name, lwp_cpptr->name))
+ pthread_mutex_lock(&ct_mutex);
+ pthread_cond_signal(&lwp_cpptr->c);
+
+ /* sleep on your own condition */
+ Debug(0, ("WaitProcess:%s going to wait \n", old_cpptr->name))
+ pthread_cond_wait(&old_cpptr->c, &ct_mutex);
+ pthread_mutex_unlock(&ct_mutex);
+
+ /* update the global pointer */
+ lwp_cpptr = old_cpptr;
+ if (lwp_cpptr->priority < Highest_runnable_priority)
+ Dispatcher();
+ return LWP_SUCCESS ;
+ }
+ return LWP_EINIT ;
+
+}
+
+int
+LWP_StackUsed(PROCESS pid, int *max, int *used)
+{
+ /* just here for compatibility */
+ *max = -1;
+ *used = -1;
+ return LWP_SUCCESS;
+}
+
+static void
+Abort_LWP(char *msg)
+{
+ Debug(0, ("Entered Abort_LWP"))
+ printf("***LWP Abort: %s\n", msg);
+ Dump_Processes();
+ Exit_LWP();
+}
+
+static void
+Create_Process_Part2(PROCESS temp)
+{
+ /* set the global Proc_Running to signal the parent */
+ pthread_mutex_lock(&run_sem);
+ Proc_Running = TRUE;
+ pthread_cond_wait(&temp->c, &run_sem);
+ pthread_mutex_unlock(&run_sem);
+ lwp_cpptr = temp;
+
+#ifdef _POSIX_THREAD_ATTR_STACKSIZE
+ pthread_attr_setstacksize(&temp->a, temp->stacksize);
+#endif
+
+ (*temp->ep)(temp->parm);
+ LWP_DestroyProcess(temp);
+}
+
+static void
+Dump_One_Process(PROCESS pid)
+{
+ int i;
+
+ printf("***LWP: Process Control Block at 0x%x\n", (int)pid);
+ printf("***LWP: Name: %s\n", pid->name);
+ if (pid->ep != NULL)
+ printf("***LWP: Initial entry point: 0x%x\n", (int)pid->ep);
+ if (pid->blockflag) printf("BLOCKED and ");
+ switch (pid->status) {
+ case READY: printf("READY"); break;
+ case WAITING: printf("WAITING"); break;
+ case DESTROYED: printf("DESTROYED"); break;
+ default: printf("unknown");
+ }
+ putchar('\n');
+ printf("***LWP: Priority: %d \tInitial parameter: 0x%x\n",
+ pid->priority, (int)pid->parm);
+
+ if (pid->eventcnt > 0) {
+ printf("***LWP: Number of events outstanding: %d\n", pid->waitcnt);
+ printf("***LWP: Event id list:");
+ for (i=0;i<pid->eventcnt;i++)
+ printf(" 0x%x", (int)pid->eventlist[i]);
+ putchar('\n');
+ }
+ if (pid->wakevent>0)
+ printf("***LWP: Number of last wakeup event: %d\n", pid->wakevent);
+}
+
+static void
+Dispatcher() /* Lightweight process dispatcher */
+{
+ void *t;
+ int my_priority;
+ PROCESS old_cpptr;
+#if 1
+ int i = Highest_runnable_priority;
+
+ Cal_Highest_runnable_priority();
+ if (Highest_runnable_priority != i)
+ printf("hipri was %d actually %d\n", i, Highest_runnable_priority);
+ Highest_runnable_priority = i;
+#endif
+ my_priority = lwp_cpptr->priority;
+ Debug(0, ("Dispatcher: %d runnable at pri %d hi %d blk %d",
+ runnable[my_priority].count, my_priority,
+ Highest_runnable_priority, PRE_Block));
+ PRE_Block = 1;
+ if ((my_priority < Highest_runnable_priority) ||
+ (runnable[my_priority].count > 0))
+ {
+ Debug(0, ("Dispatcher: %s is now yielding", lwp_cpptr->name));
+ /* I have to quit */
+ old_cpptr = lwp_cpptr;
+ lwpinsert(old_cpptr, &runnable[my_priority]);
+ gettimeofday(&old_cpptr->lastReady, 0);
+ lwp_cpptr = runnable[Highest_runnable_priority].head;
+
+ /* remove next process from runnable queue and signal it */
+ lwpremove(lwp_cpptr, &runnable[Highest_runnable_priority]);
+ pthread_mutex_lock(&ct_mutex);
+ Debug(0, ("Dispatcher: %s going to signal %s condition\n",
+ old_cpptr->name, lwp_cpptr->name))
+
+ pthread_cond_signal(&lwp_cpptr->c);
+
+ /* now sleep until somebody wakes me */
+ Debug(0, ("Dispatcher: %s going to wait on own condition\n",
+ old_cpptr->name))
+ pthread_cond_wait(&old_cpptr->c, &ct_mutex);
+ pthread_mutex_unlock(&ct_mutex);
+
+ /* update global pointer */
+ lwp_cpptr = old_cpptr;
+ } else {
+ Debug(0, ("Dispatcher: %s still running", lwp_cpptr->name))
+ }
+ /* make sure HRP is set correct */
+ Highest_runnable_priority = lwp_cpptr->priority;
+ if (lwp_cpptr->status == DESTROYED){
+ /* the process was runnable but got destroyed by somebody */
+ Free_PCB(lwp_cpptr);
+ Cal_Highest_runnable_priority();
+ lwp_cpptr = runnable[Highest_runnable_priority].head;
+ lwpremove(lwp_cpptr, &runnable[Highest_runnable_priority]);
+
+ pthread_mutex_lock(&ct_mutex);
+ pthread_cond_signal(&lwp_cpptr->c);
+ pthread_mutex_unlock(&ct_mutex);
+ pthread_exit(t);
+ }
+#if 0
+ if (PRE_Block != 1) Abort_LWP("PRE_Block not 1");
+#endif
+ PRE_Block = 0;
+}
+
+
+static void
+Free_PCB(PROCESS pid)
+{
+ Debug(0, ("Entered Free_PCB"))
+
+ if (pid->eventlist != NULL) free((char *)pid->eventlist);
+ free((char *)pid);
+}
+
+static void
+Initialize_PCB(PROCESS temp, int priority, char *stack, int stacksize,
+ void (*ep)(), char *parm, char *name)
+{
+ register int i = 0;
+
+ Debug(0, ("Entered Initialize_PCB"))
+ if (name != NULL)
+ while (((temp -> name[i] = name[i]) != '\0') && (i < 31)) i++;
+ temp -> name[31] = '\0';
+ temp -> status = READY;
+ temp -> eventlist = (char **)malloc(EVINITSIZE*sizeof(char *));
+ temp -> eventlistsize = EVINITSIZE;
+ temp -> eventcnt = 0;
+ temp -> wakevent = 0;
+ temp -> waitcnt = 0;
+ temp -> blockflag = 0;
+ temp -> iomgrRequest = 0;
+ temp -> priority = priority;
+ temp -> index = lwp_nextindex++;
+ temp -> ep = ep;
+ temp -> parm = parm;
+ temp -> misc = NULL; /* currently unused */
+ temp -> next = NULL;
+ temp -> prev = NULL;
+ temp -> rused = 0;
+ temp -> level = 1; /* non-preemptable */
+ timerclear(&temp->lastReady);
+
+ /* initialize the mutex and condition */
+ pthread_mutex_init(&temp->m, NULL);
+ pthread_cond_init(&temp->c, NULL);
+
+ Debug(0, ("Leaving Initialize_PCB\n"))
+}
+
+static int
+Internal_Signal(register char *event)
+{
+ int rc = LWP_ENOWAIT;
+ register int i;
+
+ Debug(0, ("Entered Internal_Signal [event id 0x%x]", (int)event));
+ if (!lwp_init) return LWP_EINIT;
+ if (event == NULL) return LWP_EBADEVENT;
+
+ for_all_elts(temp, blocked, { /* for all pcb's on the blocked q */
+ if (temp->status == WAITING)
+ for (i=0; i < temp->eventcnt; i++) { /* check each event in list */
+ if (temp -> eventlist[i] == event) {
+ temp -> eventlist[i] = NULL;
+ rc = LWP_SUCCESS;
+ Debug(0, ("decrementing %s to %d", temp->name, (temp->waitcnt-1)));
+ /* reduce waitcnt by 1 for the signal */
+ /* if wcount reaches 0 then make the process runnable */
+ if (--temp->waitcnt == 0) {
+ temp -> status = READY;
+ temp -> wakevent = i+1;
+ lwpmove(temp, &blocked, &runnable[temp->priority]);
+ gettimeofday(&temp->lastReady, 0);
+ Highest_runnable_priority =
+ MAX(Highest_runnable_priority, temp->priority);
+ Debug(0, ("marked runnable. hi_pri %d, %d at %d", Highest_runnable_priority, runnable[temp->priority].count, temp->priority));
+ break;
+ }
+ }
+ }
+ })
+ return rc;
+}
+
+/* places the maximum of runnable task priorities in the global variable -
+ * Highest_runnable_priority. No runnable process is an error */
+static void
+Cal_Highest_runnable_priority()
+{
+ int i;
+ for (i = LWP_MAX_PRIORITY; runnable[i].count == 0 && i >=0; i--);
+#if 0
+ if (i < 0)
+ Abort_LWP("No ready processes");
+ else
+ Highest_runnable_priority = i;
+#else
+ if (i >= 0)
+ Highest_runnable_priority = i;
+#endif
+}
diff --git a/usr.sbin/afs/src/lwp/plwp.h b/usr.sbin/afs/src/lwp/plwp.h
new file mode 100644
index 00000000000..4857eef176d
--- /dev/null
+++ b/usr.sbin/afs/src/lwp/plwp.h
@@ -0,0 +1,191 @@
+/* $OpenBSD: plwp.h,v 1.1 1999/04/30 01:59:13 art Exp $ */
+#ifndef LWP_INCLUDED
+#define LWP_INCLUDED
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_POSIX_SIGNALS
+#define AFS_POSIX_SIGNALS 1
+#endif
+#define AFS_LWP_MINSTACKSIZE (100 * 1024)
+#include <sys/time.h>
+#include <signal.h>
+
+#ifndef LWP_KERNEL
+extern
+#endif
+char lwp_debug; /* ON = show LWP debugging trace */
+
+extern int lwp_stackUseEnabled;
+extern int lwp_MaxStackSeen;
+#define LWP_ActiveProcess (lwp_cpptr+0)
+
+#define LWP_VERSION 210888001
+
+#define LWP_SUCCESS 0
+#define LWP_EBADPID -1
+#define LWP_EBLOCKED -2
+#define LWP_EINIT -3
+#define LWP_EMAXPROC -4
+#define LWP_ENOBLOCK -5
+#define LWP_ENOMEM -6
+#define LWP_ENOPROCESS -7
+#define LWP_ENOWAIT -8
+#define LWP_EBADCOUNT -9
+#define LWP_EBADEVENT -10
+#define LWP_EBADPRI -11
+#define LWP_NO_STACK -12
+/* These two are for the signal mechanism. */
+#define LWP_EBADSIG -13 /* bad signal number */
+#define LWP_ESYSTEM -14 /* system call failed */
+/* These are for the rock mechanism */
+#define LWP_ENOROCKS -15 /* all rocks are in use */
+#define LWP_EBADROCK -16 /* the specified rock does not exist */
+
+
+/* Maximum priority permissible (minimum is always 0) */
+#define LWP_MAX_PRIORITY 4
+
+/* Usual priority used by user LWPs */
+#define LWP_NORMAL_PRIORITY (LWP_MAX_PRIORITY-1)
+
+#define LWP_SignalProcess(event) LWP_INTERNALSIGNAL(event, 1)
+#define LWP_NoYieldSignal(event) LWP_INTERNALSIGNAL(event, 0)
+
+/* Users aren't really supposed to know what a pcb is, but .....*/
+typedef struct lwp_pcb *PROCESS;
+
+/* Action to take on stack overflow. */
+#define LWP_SOQUIET 1 /* do nothing */
+#define LWP_SOABORT 2 /* abort the program */
+#define LWP_SOMESSAGE 3 /* print a message and be quiet */
+extern int lwp_overflowAction;
+
+/* Tells if stack size counting is enabled. */
+extern int lwp_stackUseEnabled;
+
+int LWP_QWait(void);
+int LWP_QSignal(PROCESS);
+int LWP_Init(int, int, PROCESS *);
+int LWP_InitializeProcessSupport(int, PROCESS *);
+int LWP_TerminateProcessSupport();
+int LWP_CreateProcess(void (*)(), int, int, char *, char *, PROCESS *);
+int LWP_CurrentProcess(PROCESS *);
+int LWP_DestroyProcess(PROCESS);
+int LWP_DispatchProcess();
+int LWP_GetProcessPriority(PROCESS, int *);
+int LWP_INTERNALSIGNAL(void *, int);
+int LWP_WaitProcess(char *);
+int LWP_MwaitProcess(int, char **);
+int LWP_StackUsed(PROCESS, int *, int *);
+int LWP_NewRock(int, char *);
+int LWP_GetRock(int, char **);
+char *LWP_Name();
+int LWP_Index();
+int LWP_HighestIndex();
+
+int IOMGR_SoftSig(void (*)(), char *);
+int IOMGR_Initialize(void);
+int IOMGR_Finalize(void);
+long IOMGR_Poll(void);
+int IOMGR_Select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
+int IOMGR_Cancel(register PROCESS);
+int IOMGR_Signal(int, char *);
+int IOMGR_CancelSignal(int);
+void IOMGR_Sleep(unsigned int);
+
+int FT_Init(int, int);
+#if __GNUC__ >= 2
+struct timezone;
+#endif
+int FT_GetTimeOfDay(register struct timeval *, register struct timezone *);
+int TM_GetTimeOfDay(struct timeval *, struct timezone *);
+int FT_AGetTimeOfDay(struct timeval *, struct timezone *);
+unsigned int FT_ApproxTime(void);
+
+#include <pthread.h>
+
+/* Initial size of eventlist in a PCB; grows dynamically */
+#define EVINITSIZE 5
+
+struct rock
+ {/* to hide things associated with this LWP under */
+ int tag; /* unique identifier for this rock */
+ pthread_key_t val;
+ /*char *value;*/ /* pointer to some arbitrary data structure */
+ };
+
+#define MAXROCKS 4 /* max no. of rocks per LWP */
+
+struct lwp_pcb { /* process control block */
+ char name[32];
+ int rc;
+ char status;
+ char **eventlist;
+ char eventlistsize;
+ int eventcnt;
+ int wakevent;
+ int waitcnt;
+ char blockflag;
+ int priority;
+ PROCESS misc;
+ char *stack;
+ int stacksize;
+ long stackcheck;
+ void (*ep)(char *);
+ char *parm;
+ int rused;
+ struct rock rlist[MAXROCKS];
+ PROCESS next, prev;
+ int level;
+ struct IoRequest *iomgrRequest;
+ int index;
+ struct timeval lastReady;
+ pthread_mutex_t m;
+ pthread_cond_t c;
+ pthread_attr_t a;
+};
+
+extern int lwp_nextindex; /* Next lwp index to assign */
+
+extern PROCESS lwp_cpptr; /* pointer to current process pcb */
+struct lwp_ctl { /* LWP control structure */
+ int processcnt; /* number of lightweight processes */
+ char *outersp; /* outermost stack pointer */
+ PROCESS outerpid; /* process carved by Initialize */
+ PROCESS first, last; /* ptrs to first and last pcbs */
+ char dsptchstack[800]; /* stack for dispatcher use only */
+};
+
+extern char PRE_Block; /* used in preemption control (in preempt.c) */
+
+/* Debugging macro */
+#ifdef LWPDEBUG
+#define lwpdebug(level, msg)\
+ if (lwp_debug > level) {\
+ printf("***LWP (0x%x): ", lwp_cpptr);\
+ printf msg;\
+ putchar('\n');\
+ fflush(stdout);\
+ }
+#else /* LWPDEBUG */
+#define lwpdebug(level, msg)
+#endif /* LWPDEBUG */
+
+#define MAXTHREADS 100
+
+#endif /* LWP_INCLUDED */
+
+
+
diff --git a/usr.sbin/afs/src/lwp/process-vpp.s b/usr.sbin/afs/src/lwp/process-vpp.s
new file mode 100644
index 00000000000..707f7c855b5
--- /dev/null
+++ b/usr.sbin/afs/src/lwp/process-vpp.s
@@ -0,0 +1,171 @@
+/* -*- text -*- */
+/*
+ * Copyright (c) 1998 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Kungliga Tekniska
+ * Högskolan and its contributors.
+ *
+ * 4. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $Id: process-vpp.s,v 1.1 1999/04/30 01:59:14 art Exp $ */
+
+/* LWP context switch for Fujitsu UXP/V */
+
+#define registers 8 /* leave room for fp, and ra */
+#define floats (registers + 12 * 4)
+#ifdef SAVE_FLOATS
+#define FRAMESIZE (floats + 15 * 8)
+#else
+#define FRAMESIZE floats
+#endif
+
+/*
+void savecontext(int (*)(void), struct savearea*, void*);
+*/
+
+ .section .text
+ .global savecontext
+ .align 8
+savecontext:
+ /* make space */
+ or %gr1, %gr0, %gr2 & st %gr2, %gr1, 4
+ addi23 %gr1, -FRAMESIZE, %gr1 & st %gr3, %gr2, %gr0
+
+ /* save registers */
+ /* XXX save more registers? */
+ st %gr4, %gr1, registers + 0
+ st %gr5, %gr1, registers + 4
+ st %gr6, %gr1, registers + 8
+ st %gr7, %gr1, registers + 12
+ st %gr8, %gr1, registers + 16
+ st %gr9, %gr1, registers + 20
+ st %gr10, %gr1, registers + 24
+ st %gr11, %gr1, registers + 28
+ st %gr12, %gr1, registers + 32
+ st %gr13, %gr1, registers + 36
+ st %gr14, %gr1, registers + 40
+ st %gr15, %gr1, registers + 44
+
+#ifdef SAVE_FLOATS
+ /* save floting point registers */
+ st.d %fr1, %gr1, floats + 0
+ st.d %fr2, %gr1, floats + 8
+ st.d %fr3, %gr1, floats + 16
+ st.d %fr4, %gr1, floats + 24
+ st.d %fr5, %gr1, floats + 32
+ st.d %fr6, %gr1, floats + 40
+ st.d %fr7, %gr1, floats + 48
+ st.d %fr8, %gr1, floats + 56
+ st.d %fr9, %gr1, floats + 64
+ st.d %fr10, %gr1, floats + 72
+ st.d %fr11, %gr1, floats + 80
+ st.d %fr12, %gr1, floats + 88
+ st.d %fr13, %gr1, floats + 96
+ st.d %fr14, %gr1, floats + 104
+ st.d %fr15, %gr1, floats + 112
+#endif
+
+ /* block */
+ addi5 %gr0, 1, %gr20
+ seti PRE_Block, %gr21
+ st.c %gr20, %gr21, 0
+
+ /* save sp */
+ st %gr1, %gr17, 0
+ /* new sp */
+ subi5 %gr18, 0, %gr0
+ brc %iccp.z, samestack
+
+ /* switch to new stack */
+ or %gr18, %gr0, %gr1
+ /* load fp */
+ ld %gr1, 0, %gr2
+
+samestack:
+ /* is this necessary? */
+ or %gr16, %gr0, %gr3
+ jmp %gr3
+
+ .type savecontext,@function
+ .size savecontext,.-savecontext
+
+/*
+void returnto(struct savearea*);
+*/
+ .global returnto
+ .align 8
+returnto:
+ seti PRE_Block, %gr17
+ st.c %gr0, %gr17, 0
+ /* restore sp */
+ ld %gr16, 0, %gr1
+ /* restore registers */
+ ld %gr1, registers + 0, %gr4
+ ld %gr1, registers + 4, %gr5
+ ld %gr1, registers + 8, %gr6
+ ld %gr1, registers + 12, %gr7
+ ld %gr1, registers + 16, %gr8
+ ld %gr1, registers + 20, %gr9
+ ld %gr1, registers + 24, %gr10
+ ld %gr1, registers + 28, %gr11
+ ld %gr1, registers + 32, %gr12
+ ld %gr1, registers + 36, %gr13
+ ld %gr1, registers + 40, %gr14
+ ld %gr1, registers + 44, %gr15
+
+#ifdef SAVE_FLOATS
+ /* restore floting point registers */
+ ld.d %gr1, floats + 0, %fr1
+ ld.d %gr1, floats + 8, %fr2
+ ld.d %gr1, floats + 16, %fr3
+ ld.d %gr1, floats + 24, %fr4
+ ld.d %gr1, floats + 32, %fr5
+ ld.d %gr1, floats + 40, %fr6
+ ld.d %gr1, floats + 48, %fr7
+ ld.d %gr1, floats + 56, %fr8
+ ld.d %gr1, floats + 64, %fr9
+ ld.d %gr1, floats + 72, %fr10
+ ld.d %gr1, floats + 80, %fr11
+ ld.d %gr1, floats + 88, %fr12
+ ld.d %gr1, floats + 96, %fr13
+ ld.d %gr1, floats + 104, %fr14
+ ld.d %gr1, floats + 112, %fr15
+#endif
+ addi23 %gr1, FRAMESIZE, %gr1
+ ld %gr1, 0, %gr3
+ ld %gr1, 4, %gr2
+
+ jmp %gr3
+
+ .type returnto,@function
+ .size returnto,.-returnto
diff --git a/usr.sbin/afs/src/lwp/rw.c b/usr.sbin/afs/src/lwp/rw.c
new file mode 100644
index 00000000000..96e19d15e02
--- /dev/null
+++ b/usr.sbin/afs/src/lwp/rw.c
@@ -0,0 +1,255 @@
+/* $OpenBSD: rw.c,v 1.1 1999/04/30 01:59:14 art Exp $ */
+/*
+****************************************************************************
+* Copyright IBM Corporation 1988, 1989 - All Rights Reserved *
+* *
+* Permission to use, copy, modify, and distribute this software and its *
+* documentation for any purpose and without fee is hereby granted, *
+* provided that the above copyright notice appear in all copies and *
+* that both that copyright notice and this permission notice appear in *
+* supporting documentation, and that the name of IBM not be used in *
+* advertising or publicity pertaining to distribution of the software *
+* without specific, written prior permission. *
+* *
+* IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL *
+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL IBM *
+* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY *
+* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER *
+* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING *
+* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
+****************************************************************************
+*/
+
+/*
+ (Multiple) readers & writers test of LWP stuff.
+
+Created: 11/1/83, J. Rosenberg
+
+*/
+
+#include <sys/time.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <lwp.h>
+#include "lock.h"
+#include "preempt.h"
+
+#define DEFAULT_READERS 5
+
+#define STACK_SIZE (16*1024)
+
+/* The shared queue */
+typedef struct QUEUE {
+ struct QUEUE *prev, *next;
+ char *data;
+ struct Lock lock;
+} queue;
+
+queue *init()
+{
+ queue *q;
+
+ q = (queue *) malloc(sizeof(queue));
+ q -> prev = q -> next = q;
+ return(q);
+}
+
+char empty(queue *q)
+{
+ return (q->prev == q && q->next == q);
+}
+
+void insert(queue *q, char *s)
+{
+ queue *new;
+
+ new = (queue *) malloc(sizeof(queue));
+ new -> data = s;
+ new -> prev = q -> prev;
+ q -> prev -> next = new;
+ q -> prev = new;
+ new -> next = q;
+}
+
+char *Remove(queue *q)
+{
+ queue *old;
+ char *s;
+
+ if (empty(q)) {
+ printf("Remove from empty queue");
+ abort();
+ }
+
+ old = q -> next;
+ q -> next = old -> next;
+ q -> next -> prev = q;
+ s = old -> data;
+ free(old);
+ return(s);
+}
+
+queue *q;
+
+int asleep; /* Number of processes sleeping -- used for
+ clean termination */
+
+static int read_process(int id)
+{
+ int foo;
+ printf("\t[Reader %d]\n", id);
+ LWP_NewRock(1, id);
+ LWP_DispatchProcess(); /* Just relinquish control for now */
+
+ PRE_PreemptMe();
+ for (;;) {
+ register int i;
+
+ /* Wait until there is something in the queue */
+ asleep++;
+ ObtainReadLock(&q->lock);
+ while (empty(q)) {
+ ReleaseReadLock(&q->lock);
+ LWP_WaitProcess((void *)q);
+ ObtainReadLock(&q->lock);
+ }
+ asleep--;
+ for (i=0; i<10000; i++) ;
+ PRE_BeginCritical();
+ LWP_GetRock(1, &foo);
+ printf("[%d: %s]\n", foo, Remove(q));
+ PRE_EndCritical();
+ ReleaseReadLock(&q->lock);
+ LWP_DispatchProcess();
+ }
+}
+
+static void write_process()
+{
+ static char *messages[] =
+ {
+ "Mary had a little lamb,",
+ "Its fleece was white as snow,",
+ "And everywhere that Mary went,",
+ "The lamb was sure to go",
+ "Mary had a little lamb,",
+ "Its fleece was white as snow,",
+ "And everywhere that Mary went,",
+ "The lamb was sure to go",
+ "Mary had a little lamb,",
+ "Its fleece was white as snow,",
+ "And everywhere that Mary went,",
+ "The lamb was sure to go",
+ "Mary had a little lamb,",
+ "Its fleece was white as snow,",
+ "And everywhere that Mary went,",
+ "The lamb was sure to go",
+ "Mary had a little lamb,",
+ "Its fleece was white as snow,",
+ "And everywhere that Mary went,",
+ "The lamb was sure to go",
+ "Mary had a little lamb,",
+ "Its fleece was white as snow,",
+ "And everywhere that Mary went,",
+ "The lamb was sure to go",
+ "Mary had a little lamb,",
+ "Its fleece was white as snow,",
+ "And everywhere that Mary went,",
+ "The lamb was sure to go",
+ "Mary had a little lamb,",
+ "Its fleece was white as snow,",
+ "And everywhere that Mary went,",
+ "The lamb was sure to go",
+ "Mary had a little lamb,",
+ "Its fleece was white as snow,",
+ "And everywhere that Mary went,",
+ "The lamb was sure to go",
+ "Mary had a little lamb,",
+ "Its fleece was white as snow,",
+ "And everywhere that Mary went,",
+ "The lamb was sure to go",
+ 0
+ };
+ char **mesg;
+
+ printf("\t[Writer]\n");
+ PRE_PreemptMe();
+
+ /* Now loop & write data */
+ for (mesg=messages; *mesg!=0; mesg++) {
+ ObtainWriteLock(&q->lock);
+ insert(q, *mesg);
+ ReleaseWriteLock(&q->lock);
+ LWP_SignalProcess(q);
+ }
+
+ asleep++;
+}
+
+/*
+ Arguments:
+ 0: Unix junk, ignore
+ 1: Number of readers to create (default is DEFAULT_READERS)
+ 2: # msecs for interrupt (to satisfy Larry)
+ 3: Present if lwp_debug to be set
+*/
+
+
+int
+main(int argc, char **argv)
+{
+ int nreaders, i;
+ long interval; /* To satisfy Brad */
+ PROCESS *readers;
+ PROCESS writer, master;
+ struct timeval tv;
+ char rname[9];
+
+ printf("\n*Readers & Writers*\n\n");
+ setbuf(stdout, 0);
+
+ /* Determine # readers */
+ if (argc == 1)
+ nreaders = DEFAULT_READERS;
+ else
+ sscanf(*++argv, "%d", &nreaders);
+ printf("[There will be %d readers]\n", nreaders);
+
+ interval = (argc >= 3 ? atoi(*++argv)*1000 : 50000);
+
+ if (argc == 4) lwp_debug = 1;
+ LWP_InitializeProcessSupport(0, &master);
+ printf("[Support initialized]\n");
+ tv.tv_sec = 0;
+ tv.tv_usec = interval;
+ PRE_InitPreempt(&tv);
+
+ /* Initialize queue */
+ q = init();
+
+ /* Initialize lock */
+ Lock_Init(&q->lock);
+
+ asleep = 0;
+ /* Now create readers */
+ printf("[Creating Readers...\n");
+ readers = (PROCESS *) calloc(nreaders, sizeof(PROCESS));
+ for (i=0; i<nreaders; i++) {
+ sprintf(rname, "Reader %d", i);
+ LWP_CreateProcess((void *)(read_process), STACK_SIZE, 0, (char *)i,
+ rname, &readers[i]);
+ }
+ printf("done]\n");
+
+ printf("\t[Creating Writer...\n");
+ LWP_CreateProcess(write_process, STACK_SIZE, 1, 0, "Writer", &writer);
+ printf("done]\n");
+
+ /* Now loop until everyone's done */
+ while (asleep != nreaders+1) LWP_DispatchProcess();
+ /* Destroy the readers */
+ for (i=nreaders-1; i>=0; i--) LWP_DestroyProcess(readers[i]);
+ printf("\n*Exiting*\n");
+ return 0;
+}
diff --git a/usr.sbin/afs/src/rx/rx-new.h b/usr.sbin/afs/src/rx/rx-new.h
new file mode 100644
index 00000000000..f335e7a0fe4
--- /dev/null
+++ b/usr.sbin/afs/src/rx/rx-new.h
@@ -0,0 +1,239 @@
+/* $OpenBSD: rx-new.h,v 1.1 1999/04/30 01:59:14 art Exp $ */
+/*
+ * rx.h,v 1.7 1995/04/11 06:07:07 assar Exp
+ */
+
+#ifndef _RX_
+#define _RX_
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <list.h>
+#include <pthread.h>
+#include <thrpool.h>
+
+#include <rx_pkt.h>
+
+/* XXX - This should be moved somewhere else and replaced with XDR */
+
+typedef u_long unsigned32;
+typedef u_short unsigned16;
+
+/* Security garbage */
+
+typedef struct rx_securityClass {
+} rx_securityClass;
+
+typedef struct rx_connection rx_connection;
+
+typedef struct rx_call rx_call;
+
+typedef struct rx_service rx_service;
+
+#define RX_MAXDATA 1444 /* XXX - ??? */
+
+
+typedef struct rx_wirepacket {
+ rx_header header;
+ char data[RX_MAXDATA];
+} rx_wirepacket;
+
+/*
+ * There are two different types of acks.
+ * soft ack means that the packet has been receieved at the other end,
+ * but the sender should not throw away the packet yet. The receiver
+ * can still drop the packet or not give it to the application.
+ * The point of the soft acks is mainly flow-control.
+ *
+ * A hard ack means that the packet has been acknowledged by the
+ * application. Then the packet can be thrown away.
+ *
+ */
+
+typedef enum {
+ RX_PKT_SOFT_ACK = 1
+} rx_packet_flags;
+
+typedef struct rx_packet {
+ rx_wirepacket wire;
+ unsigned datalen;
+ rx_call *call;
+ rx_packet_flags flags;
+} rx_packet;
+
+
+/* every call - i.e. RPC transaction */
+
+struct rx_call {
+ enum { SENDING, RECEIVING } mode;
+ u_long callno; /* Call # of this connection */
+ u_long seqno; /* Seq # for packets */
+ int channelid; /* What channel are we using? */
+ rx_connection *conn;
+ List *recvpackets; /* List of received packets */
+#if 0
+ List *ooopackets; /* Packets rec'd out-of-order */
+#endif
+ rx_packet *thispacket; /* This packet, sending or receiving */
+ char *ptr; /* Here we should write data */
+ unsigned nleft; /* How much data there is left */
+ pthread_mutex_t mutex; /* Synchronisation */
+ pthread_cond_t cond;
+};
+
+/* This represents the on-going communication, i.e. a connection */
+
+typedef enum {
+ RX_CONN_SERVER, /* This is a server */
+ RX_CONN_CLIENT /* The other side is a server */
+} rx_connection_type;
+
+#define RX_WINDOW 15
+
+struct rx_connection {
+ time_t epoch; /* Time when this connection started */
+ u_long connid; /* Connection ID. How? */
+ struct sockaddr_in peer; /* The one we're talking to */
+ u_long serialno; /* Next serial number to use */
+ u_long callno[MAXCALLS]; /* Next call number to use */
+ rx_call *calls[MAXCALLS]; /* The on-going calls */
+ u_char secindex; /* Security index */
+ u_short serviceid; /* Service ID */
+ rx_connection_type type; /* Type of connection C-S or S-C */
+ u_long maxnoacked; /* Max packet sent and soft-acked */
+ List *packets; /* Not yet acked sent packets */
+ u_long window; /* Size of the window */
+ pthread_cond_t condsend; /* Conditional variable for sending */
+ pthread_mutex_t mutexsend; /* Mutex for above */
+ pthread_cond_t condrecv;
+ pthread_mutex_t mutexrecv;
+ rx_service *service; /* Service if server, else NULL */
+};
+
+/*
+ * About packets:
+ *
+ * Here we keep the packets that have been sent but not yet
+ * hard-acked. When a packet has been soft-acked we set a flag in the
+ * packet_flags and stop the resend-timer.
+ */
+
+struct rx_service {
+ u_short port;
+ u_short serviceid;
+ char *servicename;
+ int (*serviceproc)(rx_call *);
+ Thrpool *thrpool;
+};
+
+/* functions */
+
+int rx_Init (int port);
+
+rx_connection *rx_NewConnection (struct in_addr host, u_short port,
+ u_short service,
+ rx_securityClass *sec,
+ int secindex);
+
+void rx_DestroyConnection (rx_connection *);
+
+rx_call *rx_NewCall (rx_connection *);
+
+int rx_EndCall (rx_call *, int);
+
+rx_service *rx_NewService(u_short port, u_short serviceid,
+ char *servicename, rx_securityClass **so,
+ int nso, int (*serviceproc)(rx_call *));
+
+int rx_Write (rx_call *, void *, int);
+int rx_Read (rx_call *, void *, int);
+int rx_FlushWrite (rx_call *call);
+
+
+#endif /* _RX_ */
+
+
+
+
+/* Old garbage */
+
+#if 0
+
+/* header of a RPC packet */
+/* We should use XDR on this too. */
+
+typedef enum {
+ HT_DATA = 1,
+ HT_ACK = 2,
+ HT_BUSY = 3,
+ HT_ABORT = 4,
+ HT_ACKALL = 5,
+ HT_CHAL = 6,
+ HT_RESP = 7,
+ HT_DEBUG = 8
+} rx_header_type;
+
+/* For flags in header */
+
+enum {
+ HF_CLIENT_INITIATED = 1,
+ HF_REQ_ACK = 2,
+ HF_LAST = 4,
+ HF_MORE = 8};
+
+#define MAXCALLS 4
+
+#define CALL_MASK (MAXCALLS-1)
+#define CONNID_MASK (~(MAXCALLS-1))
+
+typedef struct rx_header {
+ unsigned32 epoch;
+ unsigned32 connid; /* And channel ID */
+ unsigned32 callid;
+ unsigned32 seqno; /* Call-based number */
+ unsigned32 serialno; /* Unique number */
+ u_char type;
+ u_char flags;
+ u_char status;
+ u_char secindex;
+ unsigned16 reserved; /* ??? verifier? */
+ unsigned16 serviceid;
+/* This should be the other way around according to everything but */
+/* tcpdump */
+} rx_header;
+
+#endif
+
+#if 0
+
+typedef enum {
+ RX_ACK_REQUESTED = 1,
+ RX_ACK_DUPLICATE = 2,
+ RX_ACK_OUT_OF_SEQUENCE = 3,
+ RX_ACK_EXEEDS_WINDOW = 4,
+ RX_ACK_NOSPACE = 5,
+ RX_ACK_PING = 6,
+ RX_ACK_PING_RESPONSE = 7,
+ RX_ACK_DELAY = 8
+} rx_ack_reason;
+
+typedef enum {
+ RX_ACK_TYPE_NACK = 0,
+ RX_ACK_TYPE_ACK = 1
+} rx_ack_type;
+
+#define RXMAXACKS 255
+
+typedef struct rx_ack_packet {
+ unsigned16 bufferspace;
+ unsigned16 maxskew;
+ unsigned32 firstpacket; /* First packet in acks below */
+ unsigned32 prevpacket;
+ unsigned32 serial; /* Packet that prompted this one */
+ u_char reason; /* rx_ack_reason */
+ u_char nacks; /* # of acks */
+ u_char acks[RXMAXACKS]; /* acks (rx_ack_type) */
+} rx_ack_packet;
+
+#endif
diff --git a/usr.sbin/afs/src/rx/rxgencon.h b/usr.sbin/afs/src/rx/rxgencon.h
new file mode 100644
index 00000000000..19bed98dc2b
--- /dev/null
+++ b/usr.sbin/afs/src/rx/rxgencon.h
@@ -0,0 +1,39 @@
+/* $OpenBSD: rxgencon.h,v 1.1 1999/04/30 01:59:15 art Exp $ */
+/*
+****************************************************************************
+* Copyright IBM Corporation 1988, 1989 - All Rights Reserved *
+* *
+* Permission to use, copy, modify, and distribute this software and its *
+* documentation for any purpose and without fee is hereby granted, *
+* provided that the above copyright notice appear in all copies and *
+* that both that copyright notice and this permission notice appear in *
+* supporting documentation, and that the name of IBM not be used in *
+* advertising or publicity pertaining to distribution of the software *
+* without specific, written prior permission. *
+* *
+* IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL *
+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL IBM *
+* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY *
+* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER *
+* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING *
+* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
+****************************************************************************
+*/
+
+/* $KTH: rxgencon.h,v 1.1 1999/02/05 06:09:06 lha Exp $ */
+
+#ifndef _RXGEN_CONSTS_
+#define _RXGEN_CONSTS_
+
+/* These are some rxgen-based (really arbitrary) error codes... */
+#define RXGEN_SUCCESS 0
+#define RXGEN_CC_MARSHAL -450
+#define RXGEN_CC_UNMARSHAL -451
+#define RXGEN_SS_MARSHAL -452
+#define RXGEN_SS_UNMARSHAL -453
+#define RXGEN_DECODE -454
+#define RXGEN_OPCODE -455
+#define RXGEN_SS_XDRFREE -456
+#define RXGEN_CC_XDRFREE -457
+
+#endif /* _RXGEN_CONSTS_ */
diff --git a/usr.sbin/afs/src/rxdef/rx_pkt.xg b/usr.sbin/afs/src/rxdef/rx_pkt.xg
new file mode 100644
index 00000000000..ce5743aa1f2
--- /dev/null
+++ b/usr.sbin/afs/src/rxdef/rx_pkt.xg
@@ -0,0 +1,77 @@
+/* rx_pkt.xg,v 1.3 1994/12/27 03:37:04 assar Exp */
+
+/* header of a RPC packet */
+
+enum rx_header_type {
+ HT_DATA = 1,
+ HT_ACK = 2,
+ HT_BUSY = 3,
+ HT_ABORT = 4,
+ HT_ACKALL = 5,
+ HT_CHAL = 6,
+ HT_RESP = 7,
+ HT_DEBUG = 8
+};
+
+/* For flags in header */
+
+enum rx_header_flag {
+ HF_CLIENT_INITIATED = 1,
+ HF_REQ_ACK = 2,
+ HF_LAST = 4,
+ HF_MORE = 8
+};
+
+%#define MAXCALLS 4
+
+%#define CALL_MASK (MAXCALLS-1)
+%#define CONNID_MASK (~(MAXCALLS-1))
+
+const RX_HEADER_SIZE=28;
+
+struct rx_header {
+ unsigned epoch;
+ unsigned connid; /* And channel ID */
+ unsigned callid;
+ unsigned seqno;
+ unsigned serialno;
+ u_char type;
+ u_char flags;
+ u_char status;
+ u_char secindex;
+ u_short reserved; /* ??? verifier? */
+ u_short serviceid;
+/* This should be the other way around according to everything but */
+/* tcpdump */
+};
+
+enum rx_ack_reason {
+ RX_ACK_REQUESTED = 1,
+ RX_ACK_DUPLICATE = 2,
+ RX_ACK_OUT_OF_SEQUENCE = 3,
+ RX_ACK_EXEEDS_WINDOW = 4,
+ RX_ACK_NOSPACE = 5,
+ RX_ACK_PING = 6,
+ RX_ACK_PING_RESPONSE = 7,
+ RX_ACK_DELAY = 8
+};
+
+enum rx_ack_type {
+ RX_ACK_TYPE_NACK = 0,
+ RX_ACK_TYPE_ACK = 1
+};
+
+const RXMAXACKS=255;
+
+struct rx_ack_header {
+ u_short bufferspace; /* # of packet buffers available */
+ u_short maxskew;
+ u_long firstpacket; /* First packet in acks below */
+ u_long prevpacket;
+ u_long serial; /* Packet that prompted this one */
+ u_char reason; /* rx_ack_reason */
+/* u_char nacks;*/ /* # of acks */
+ u_char acks<u_char>;
+/* u_char acks[RXMAXACKS];*/ /* acks (rx_ack_type) */
+};
+
diff --git a/usr.sbin/afs/src/util/heap.c b/usr.sbin/afs/src/util/heap.c
new file mode 100644
index 00000000000..959c0c42ed1
--- /dev/null
+++ b/usr.sbin/afs/src/util/heap.c
@@ -0,0 +1,295 @@
+/* $OpenBSD: heap.c,v 1.1 1999/04/30 01:59:17 art Exp $ */
+/*
+ * Copyright (c) 1998 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the Kungliga Tekniska
+ * Högskolan and its contributors.
+ *
+ * 4. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Heap
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$KTH: heap.c,v 1.1 1998/12/28 00:14:40 assar Exp $");
+#endif
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "heap.h"
+
+/*
+ * Allocate a new heap of size `sz' with compare function `cmp'.
+ */
+
+Heap *
+heap_new (unsigned sz, heap_cmp_fn cmp)
+{
+ Heap *ret;
+ int i;
+
+ ret = malloc (sizeof(*ret));
+ if (ret == NULL)
+ return ret;
+
+ ret->cmp = cmp;
+ ret->max_sz = sz;
+ ret->sz = 0;
+ ret->data = malloc (sz * sizeof(*ret->data));
+ if (ret->data == NULL) {
+ free (ret);
+ return NULL;
+ }
+ for (i = 0; i < sz; ++i) {
+ ret->data[i].data = NULL;
+ ret->data[i].ptr = NULL;
+ }
+ return ret;
+}
+
+static inline unsigned
+parent (unsigned n)
+{
+ return (n + 1) / 2 - 1;
+}
+
+static inline unsigned
+left_child (unsigned n)
+{
+ return 2 * n + 1;
+}
+
+static inline unsigned
+right_child (unsigned n)
+{
+ return 2 * n + 2;
+}
+
+static heap_ptr dummy;
+
+/*
+ *
+ */
+
+static void
+assign (Heap *h, unsigned n, heap_element el)
+{
+ h->data[n] = el;
+ *(h->data[n].ptr) = n;
+}
+
+/*
+ *
+ */
+
+static void
+upheap (Heap *h, unsigned n)
+{
+ heap_element v = h->data[n];
+
+ while (n > 0 && (*h->cmp)(h->data[parent(n)].data, v.data) > 0) {
+ assign (h, n, h->data[parent(n)]);
+ n = parent(n);
+ }
+ assign (h, n, v);
+}
+
+/*
+ *
+ */
+
+static void
+downheap (Heap *h, unsigned n)
+{
+ heap_element v = h->data[n];
+
+ while (n < h->sz / 2) {
+ int cmp1, cmp2;
+ unsigned new_n;
+
+ assert (left_child(n) < h->sz);
+
+ new_n = left_child(n);
+
+ cmp1 = (*h->cmp)(v.data, h->data[new_n].data);
+
+ if (right_child(n) < h->sz) {
+ cmp2 = (*h->cmp)(v.data, h->data[right_child(n)].data);
+ if (cmp2 > cmp1) {
+ cmp1 = cmp2;
+ new_n = right_child(n);
+ }
+ }
+
+ if (cmp1 > 0) {
+ assign (h, n, h->data[new_n]);
+ n = new_n;
+ } else {
+ break;
+ }
+ }
+ assign (h, n, v);
+}
+
+/*
+ * Insert a new element `data' into `h'.
+ * Return 0 if succesful or else -1.
+ */
+
+int
+heap_insert (Heap *h, const void *data, heap_ptr *ptr)
+{
+ assert (data != NULL);
+
+ if (h->sz == h->max_sz) {
+ unsigned new_sz = h->max_sz * 2;
+ heap_element *tmp;
+
+ tmp = realloc (h->data, new_sz * sizeof(*h->data));
+ if (tmp == NULL)
+ return -1;
+ h->max_sz = new_sz;
+ h->data = tmp;
+ }
+ if (ptr == NULL)
+ ptr = &dummy;
+
+ h->data[h->sz].data = data;
+ h->data[h->sz].ptr = ptr;
+ upheap (h, h->sz);
+ ++h->sz;
+ return 0;
+}
+
+/*
+ * Return the head of the heap `h' (or NULL if it's empty).
+ */
+
+const void *
+heap_head (Heap *h)
+{
+ if (h->sz == 0)
+ return NULL;
+ else
+ return h->data[0].data;
+}
+
+/*
+ * Remove element `n' from the heap `h'
+ */
+
+static void
+remove_this (Heap *h, unsigned n)
+{
+ assert (n < h->sz);
+
+ --h->sz;
+ h->data[n] = h->data[h->sz];
+ h->data[h->sz].data = NULL;
+ h->data[h->sz].ptr = NULL;
+ if (n != h->sz) {
+ downheap (h, n);
+ upheap (h, n);
+ }
+}
+
+/*
+ * Remove the head from the heap `h'.
+ */
+
+void
+heap_remove_head (Heap *h)
+{
+ remove_this (h, 0);
+}
+
+/*
+ * Remove this very element from the heap `h'.
+ * Return 0 if succesful and -1 if it couldn't be found.
+ */
+
+int
+heap_remove (Heap *h, heap_ptr ptr)
+{
+ if (h->sz == 0)
+ return -1;
+
+ remove_this (h, ptr);
+ return 0;
+}
+
+/*
+ * Delete the heap `h'
+ */
+
+void
+heap_delete (Heap *h)
+{
+ free (h->data);
+ free (h);
+}
+
+/*
+ *
+ */
+
+static Bool
+do_verify (Heap *h, unsigned n)
+{
+ if (left_child(n) < h->sz) {
+ if((*h->cmp)(h->data[n].data, h->data[left_child(n)].data) > 0)
+ return FALSE;
+ if (!do_verify (h, left_child(n)))
+ return FALSE;
+ }
+ if (right_child(n) < h->sz) {
+ if((*h->cmp)(h->data[n].data, h->data[right_child(n)].data) > 0)
+ return FALSE;
+ if (!do_verify (h, right_child(n)))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+ * Verify that `h' is really a heap.
+ */
+
+Bool
+heap_verify (Heap *h)
+{
+ return do_verify (h, 0);
+}
diff --git a/usr.sbin/afs/src/util/heap.h b/usr.sbin/afs/src/util/heap.h
new file mode 100644
index 00000000000..d13bb1a30d1
--- /dev/null
+++ b/usr.sbin/afs/src/util/heap.h
@@ -0,0 +1,91 @@
+/* $OpenBSD: heap.h,v 1.1 1999/04/30 01:59:17 art Exp $ */
+/*
+ * Copyright (c) 1998 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the Kungliga Tekniska
+ * Högskolan and its contributors.
+ *
+ * 4. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * an abstract heap implementation
+ */
+
+/* $KTH: heap.h,v 1.1 1998/12/28 00:14:41 assar Exp $ */
+
+#ifndef _HEAP_
+#define _HEAP_
+
+#include "bool.h"
+
+typedef int (*heap_cmp_fn)(const void *, const void *);
+
+typedef unsigned heap_ptr;
+
+struct heap_element {
+ const void *data;
+ heap_ptr *ptr;
+};
+
+typedef struct heap_element heap_element;
+
+struct heap {
+ heap_cmp_fn cmp;
+ unsigned max_sz;
+ unsigned sz;
+ heap_element *data;
+};
+
+typedef struct heap Heap;
+
+Heap *heap_new (unsigned sz, heap_cmp_fn cmp);
+
+int
+heap_insert (Heap *h, const void *data, heap_ptr *ptr);
+
+const void *
+heap_head (Heap *h);
+
+void
+heap_remove_head (Heap *h);
+
+int
+heap_remove (Heap *h, heap_ptr ptr);
+
+void
+heap_delete (Heap *h);
+
+Bool
+heap_verify (Heap *h);
+
+#endif /* _HEAP_ */
diff --git a/usr.sbin/afs/src/util/heaptest.c b/usr.sbin/afs/src/util/heaptest.c
new file mode 100644
index 00000000000..ff0e5164eb3
--- /dev/null
+++ b/usr.sbin/afs/src/util/heaptest.c
@@ -0,0 +1,120 @@
+/* $OpenBSD: heaptest.c,v 1.1 1999/04/30 01:59:17 art Exp $ */
+/*
+ * Copyright (c) 1998, 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the Kungliga Tekniska
+ * Högskolan and its contributors.
+ *
+ * 4. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+RCSID("$KTH: heaptest.c,v 1.2 1999/02/13 05:03:25 assar Exp $");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <err.h>
+#include "heap.h"
+
+struct foo {
+ int i;
+ heap_ptr hptr;
+};
+
+static int
+cmp(const void *v1, const void *v2)
+{
+ const struct foo *foo1 = (const struct foo *)v1;
+ const struct foo *foo2 = (const struct foo *)v2;
+
+ return foo1->i - foo2->i;
+}
+
+static int
+testit (unsigned n)
+{
+ struct foo *foos, *bars;
+ Heap *h1, *h2;
+ int i;
+
+ foos = malloc (n * sizeof(*foos));
+ bars = malloc (n * sizeof(*bars));
+ assert (foos != NULL && bars != NULL);
+ h1 = heap_new (n, cmp);
+ h2 = heap_new (n, cmp);
+ assert (h1 != NULL && h2 != NULL);
+ for (i = 0; i < n; ++i) {
+ foos[i].i = bars[i].i = rand();
+ heap_insert (h1, (void *)&foos[i], NULL);
+ heap_insert (h2, (void *)&foos[i], &foos[i].hptr);
+ if (!heap_verify(h1) || !heap_verify(h2))
+ abort ();
+ }
+ for (i = 0; i < n; ++i) {
+ heap_remove (h2, foos[i].hptr);
+ if (!heap_verify(h2))
+ abort ();
+ }
+ qsort (bars, n, sizeof(*bars), cmp);
+ for (i = 0; i < n; ++i) {
+ struct foo *f = (struct foo *)heap_head (h1);
+
+ if (bars[i].i != f->i)
+ abort ();
+ heap_remove_head (h1);
+ if (!heap_verify(h1))
+ abort ();
+ }
+ heap_delete (h1);
+ heap_delete (h2);
+ free (foos);
+ free (bars);
+ return 0;
+}
+
+int
+main(int argc, char **argv)
+{
+ int i, n;
+
+ if (argc != 2)
+ errx (1, "argc != 2");
+
+ n = atoi (argv[1]);
+ for (i = 0; i < n; ++i)
+ testit (rand () % 1000);
+ return 0;
+}